summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2012-12-02 22:35:45 +0000
committerVincent Torri <vincent.torri@gmail.com>2012-12-02 22:35:45 +0000
commit7d6010b12c47a20e492da808e3192c3f87dab619 (patch)
tree26c6fd189e046a76560c0bc740b85f4d767ae399 /src
parent53fc441d5475155965d92da89502fe4634a561b2 (diff)
downloadefl-7d6010b12c47a20e492da808e3192c3f87dab619.tar.gz
merge: add escape ecore, fix several bugs
SVN revision: 79995
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am37
-rw-r--r--src/Makefile_Ecore.am88
-rw-r--r--src/Makefile_Ecore_Cocoa.am37
-rw-r--r--src/Makefile_Ecore_Con.am70
-rw-r--r--src/Makefile_Ecore_DirectFB.am34
-rw-r--r--src/Makefile_Ecore_Evas.am160
-rw-r--r--src/Makefile_Ecore_FB.am42
-rw-r--r--src/Makefile_Ecore_File.am41
-rw-r--r--src/Makefile_Ecore_Imf.am186
-rw-r--r--src/Makefile_Ecore_Input.am70
-rw-r--r--src/Makefile_Ecore_Ipc.am37
-rw-r--r--src/Makefile_Ecore_Psl1ght.am38
-rw-r--r--src/Makefile_Ecore_SDL.am38
-rw-r--r--src/Makefile_Ecore_Wayland.am40
-rw-r--r--src/Makefile_Ecore_Win32.am51
-rw-r--r--src/Makefile_Ecore_WinCE.am41
-rw-r--r--src/Makefile_Ecore_X.am126
-rw-r--r--src/Makefile_Escape.am25
-rw-r--r--src/Makefile_Evas.am64
-rw-r--r--src/lib/ecore/Ecore.h2954
-rw-r--r--src/lib/ecore/Ecore_Getopt.h419
-rw-r--r--src/lib/ecore/ecore.c878
-rw-r--r--src/lib/ecore/ecore_alloc.c132
-rw-r--r--src/lib/ecore/ecore_anim.c633
-rw-r--r--src/lib/ecore/ecore_app.c98
-rw-r--r--src/lib/ecore/ecore_events.c648
-rw-r--r--src/lib/ecore/ecore_exe.c1913
-rw-r--r--src/lib/ecore/ecore_exe_ps3.c20
-rw-r--r--src/lib/ecore/ecore_exe_win32.c1055
-rw-r--r--src/lib/ecore/ecore_exe_wince.c21
-rw-r--r--src/lib/ecore/ecore_getopt.c1936
-rw-r--r--src/lib/ecore/ecore_glib.c346
-rw-r--r--src/lib/ecore/ecore_idle_enterer.c313
-rw-r--r--src/lib/ecore/ecore_idle_exiter.c264
-rw-r--r--src/lib/ecore/ecore_idler.c247
-rw-r--r--src/lib/ecore/ecore_job.c198
-rw-r--r--src/lib/ecore/ecore_main.c2111
-rw-r--r--src/lib/ecore/ecore_pipe.c748
-rw-r--r--src/lib/ecore/ecore_poll.c490
-rw-r--r--src/lib/ecore/ecore_private.h398
-rw-r--r--src/lib/ecore/ecore_signal.c594
-rw-r--r--src/lib/ecore/ecore_thread.c1509
-rw-r--r--src/lib/ecore/ecore_throttle.c104
-rw-r--r--src/lib/ecore/ecore_time.c184
-rw-r--r--src/lib/ecore/ecore_timer.c1015
-rw-r--r--src/lib/ecore_cocoa/Ecore_Cocoa.h147
-rw-r--r--src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h285
-rw-r--r--src/lib/ecore_cocoa/ecore_cocoa.m283
-rw-r--r--src/lib/ecore_cocoa/ecore_cocoa_private.h11
-rw-r--r--src/lib/ecore_cocoa/ecore_cocoa_window.m163
-rw-r--r--src/lib/ecore_con/Ecore_Con.h1948
-rw-r--r--src/lib/ecore_con/Ecore_Con_Eet.h73
-rw-r--r--src/lib/ecore_con/dns.c7878
-rw-r--r--src/lib/ecore_con/dns.h1076
-rw-r--r--src/lib/ecore_con/ecore_con.c2596
-rw-r--r--src/lib/ecore_con/ecore_con_alloc.c101
-rw-r--r--src/lib/ecore_con/ecore_con_ares.c628
-rw-r--r--src/lib/ecore_con/ecore_con_dns.c344
-rw-r--r--src/lib/ecore_con/ecore_con_eet.c822
-rw-r--r--src/lib/ecore_con/ecore_con_info.c458
-rw-r--r--src/lib/ecore_con/ecore_con_local.c325
-rw-r--r--src/lib/ecore_con/ecore_con_local_win32.c754
-rw-r--r--src/lib/ecore_con/ecore_con_private.h390
-rw-r--r--src/lib/ecore_con/ecore_con_socks.c962
-rw-r--r--src/lib/ecore_con/ecore_con_ssl.c2141
-rw-r--r--src/lib/ecore_con/ecore_con_url.c1683
-rw-r--r--src/lib/ecore_directfb/Ecore_DirectFB.h181
-rw-r--r--src/lib/ecore_directfb/ecore_directfb.c758
-rw-r--r--src/lib/ecore_directfb/ecore_directfb_keys.h184
-rw-r--r--src/lib/ecore_directfb/ecore_directfb_private.h52
-rw-r--r--src/lib/ecore_evas/Ecore_Evas.h2256
-rw-r--r--src/lib/ecore_evas/ecore_evas.c2781
-rw-r--r--src/lib/ecore_evas/ecore_evas_buffer.c836
-rw-r--r--src/lib/ecore_evas/ecore_evas_cocoa.c584
-rw-r--r--src/lib/ecore_evas/ecore_evas_directfb.c606
-rw-r--r--src/lib/ecore_evas/ecore_evas_ews.c1469
-rw-r--r--src/lib/ecore_evas/ecore_evas_extn.c2266
-rw-r--r--src/lib/ecore_evas/ecore_evas_fb.c678
-rw-r--r--src/lib/ecore_evas/ecore_evas_private.h490
-rw-r--r--src/lib/ecore_evas/ecore_evas_psl1ght.c515
-rw-r--r--src/lib/ecore_evas/ecore_evas_sdl.c665
-rw-r--r--src/lib/ecore_evas/ecore_evas_util.c451
-rw-r--r--src/lib/ecore_evas/ecore_evas_wayland_common.c785
-rw-r--r--src/lib/ecore_evas/ecore_evas_wayland_egl.c434
-rw-r--r--src/lib/ecore_evas/ecore_evas_wayland_shm.c656
-rw-r--r--src/lib/ecore_evas/ecore_evas_win32.c1524
-rw-r--r--src/lib/ecore_evas/ecore_evas_wince.c67
-rw-r--r--src/lib/ecore_evas/ecore_evas_x.c3663
-rw-r--r--src/lib/ecore_fb/Ecore_Fb.h100
-rw-r--r--src/lib/ecore_fb/ecore_fb.c129
-rw-r--r--src/lib/ecore_fb/ecore_fb_kbd.c326
-rw-r--r--src/lib/ecore_fb/ecore_fb_keytable.h129
-rw-r--r--src/lib/ecore_fb/ecore_fb_li.c721
-rw-r--r--src/lib/ecore_fb/ecore_fb_private.h94
-rw-r--r--src/lib/ecore_fb/ecore_fb_ps2.c223
-rw-r--r--src/lib/ecore_fb/ecore_fb_ts.c362
-rw-r--r--src/lib/ecore_fb/ecore_fb_vt.c322
-rw-r--r--src/lib/ecore_file/Ecore_File.h190
-rw-r--r--src/lib/ecore_file/ecore_file.c1137
-rw-r--r--src/lib/ecore_file/ecore_file_download.c455
-rw-r--r--src/lib/ecore_file/ecore_file_monitor.c180
-rw-r--r--src/lib/ecore_file/ecore_file_monitor_inotify.c331
-rw-r--r--src/lib/ecore_file/ecore_file_monitor_poll.c340
-rw-r--r--src/lib/ecore_file/ecore_file_monitor_win32.c310
-rw-r--r--src/lib/ecore_file/ecore_file_path.c192
-rw-r--r--src/lib/ecore_file/ecore_file_private.h129
-rw-r--r--src/lib/ecore_imf/Ecore_IMF.h577
-rw-r--r--src/lib/ecore_imf/Ecore_IMF_Evas.h50
-rw-r--r--src/lib/ecore_imf/ecore_imf.c73
-rw-r--r--src/lib/ecore_imf/ecore_imf_context.c1900
-rw-r--r--src/lib/ecore_imf/ecore_imf_evas.c324
-rw-r--r--src/lib/ecore_imf/ecore_imf_module.c212
-rw-r--r--src/lib/ecore_imf/ecore_imf_private.h84
-rw-r--r--src/lib/ecore_input/Ecore_Input.h236
-rw-r--r--src/lib/ecore_input/Ecore_Input_Evas.h64
-rw-r--r--src/lib/ecore_input/ecore_input.c127
-rw-r--r--src/lib/ecore_input/ecore_input_compose.c61
-rw-r--r--src/lib/ecore_input/ecore_input_compose.h9895
-rw-r--r--src/lib/ecore_input/ecore_input_evas.c418
-rw-r--r--src/lib/ecore_input/ecore_input_evas_private.h37
-rw-r--r--src/lib/ecore_input/ecore_input_private.h37
-rw-r--r--src/lib/ecore_ipc/Ecore_Ipc.h328
-rw-r--r--src/lib/ecore_ipc/ecore_ipc.c1599
-rw-r--r--src/lib/ecore_ipc/ecore_ipc_private.h105
-rw-r--r--src/lib/ecore_sdl/Ecore_Sdl.h114
-rw-r--r--src/lib/ecore_sdl/Ecore_Sdl_Keys.h266
-rw-r--r--src/lib/ecore_sdl/ecore_sdl.c334
-rw-r--r--src/lib/ecore_sdl/ecore_sdl_private.h36
-rw-r--r--src/lib/ecore_wayland/Ecore_Wayland.h392
-rw-r--r--src/lib/ecore_wayland/ecore_wl.c497
-rw-r--r--src/lib/ecore_wayland/ecore_wl_dnd.c485
-rw-r--r--src/lib/ecore_wayland/ecore_wl_input.c1208
-rw-r--r--src/lib/ecore_wayland/ecore_wl_output.c87
-rw-r--r--src/lib/ecore_wayland/ecore_wl_private.h103
-rw-r--r--src/lib/ecore_wayland/ecore_wl_window.c707
-rw-r--r--src/lib/ecore_win32/Ecore_Win32.h526
-rw-r--r--src/lib/ecore_win32/ecore_win32.c841
-rw-r--r--src/lib/ecore_win32/ecore_win32_cursor.c305
-rwxr-xr-xsrc/lib/ecore_win32/ecore_win32_dnd.c221
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp209
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_data_object.h49
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp92
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_drop_source.h36
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp232
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_drop_target.h47
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp157
-rw-r--r--src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h50
-rw-r--r--src/lib/ecore_win32/ecore_win32_event.c1307
-rw-r--r--src/lib/ecore_win32/ecore_win32_private.h170
-rw-r--r--src/lib/ecore_win32/ecore_win32_window.c1418
-rw-r--r--src/lib/ecore_wince/Ecore_WinCE.h314
-rw-r--r--src/lib/ecore_wince/ecore_wince.c400
-rw-r--r--src/lib/ecore_wince/ecore_wince_event.c1123
-rw-r--r--src/lib/ecore_wince/ecore_wince_private.h85
-rw-r--r--src/lib/ecore_wince/ecore_wince_window.c827
-rw-r--r--src/lib/ecore_x/Ecore_X.h2407
-rw-r--r--src/lib/ecore_x/Ecore_X_Atoms.h292
-rw-r--r--src/lib/ecore_x/Ecore_X_Cursor.h87
-rw-r--r--src/lib/ecore_x/ecore_x_atoms_decl.h602
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb.c1583
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_atoms.c149
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_composite.c290
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_cursor.c400
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_damage.c155
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_dnd.c688
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_dpms.c320
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_drawable.c123
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_e.c1576
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_error.c123
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_events.c2824
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_extensions.c148
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_gc.c173
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_gesture.c203
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_icccm.c1569
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_image.c738
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_input.c274
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_keymap.c491
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_mwm.c104
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_netwm.c1604
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_pixmap.c128
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_private.h468
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_randr.c3807
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_region.c159
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_render.c225
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_screensaver.c370
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_selection.c1026
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_shape.c50
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_sync.c338
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_textlist.c509
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_vsync.c375
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_window.c2238
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_window_prop.c720
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c410
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_window_shape.c790
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c116
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_xfixes.c744
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_xinerama.c139
-rw-r--r--src/lib/ecore_x/xcb/ecore_xcb_xtest.c215
-rw-r--r--src/lib/ecore_x/xlib/ecore_x.c2242
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_atoms.c109
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_composite.c176
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_cursor.c246
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_damage.c71
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_dnd.c706
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_dpms.c247
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_drawable.c118
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_e.c1670
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_error.c126
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_events.c2523
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_fixes.c365
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_gc.c171
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_gesture.c137
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_icccm.c1214
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_image.c626
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_mwm.c106
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_netwm.c2083
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_pixmap.c121
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_private.h379
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr.c103
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr.h7
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr_11.c334
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr_12.c2438
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c463
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_randr_13.c68
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_region.c158
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_screensaver.c204
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_selection.c1021
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_sync.c159
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_test.c167
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_vsync.c351
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_window.c1727
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_window_prop.c760
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_window_shape.c658
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_xi2.c336
-rw-r--r--src/lib/ecore_x/xlib/ecore_x_xinerama.c91
-rw-r--r--src/lib/escape/Escape.h52
-rw-r--r--src/lib/escape/escape_libgen.c90
-rw-r--r--src/lib/escape/escape_libgen.h32
-rw-r--r--src/lib/escape/escape_mman.c67
-rw-r--r--src/lib/escape/escape_unistd.c186
-rw-r--r--src/lib/escape/escape_unistd.h107
-rw-r--r--src/lib/escape/sys/mman.h179
-rw-r--r--src/modules/ecore/immodules/ibus/ibus_imcontext.c822
-rw-r--r--src/modules/ecore/immodules/ibus/ibus_imcontext.h36
-rw-r--r--src/modules/ecore/immodules/ibus/ibus_module.c109
-rw-r--r--src/modules/ecore/immodules/scim/scim_imcontext.cpp2900
-rw-r--r--src/modules/ecore/immodules/scim/scim_imcontext.h42
-rw-r--r--src/modules/ecore/immodules/scim/scim_module.cpp104
-rw-r--r--src/modules/ecore/immodules/xim/ecore_imf_xim.c1555
-rw-r--r--src/utils/ecore/makekeys.c326
-rwxr-xr-xsrc/utils/ecore/mkks.sh10
251 files changed, 158641 insertions, 64 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 68b83fc598..e9c5a9bdbe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,10 +13,47 @@ if HAVE_WINDOWS
include Makefile_Evil.am
endif
+if HAVE_PS3
+include Makefile_Escape.am
+endif
+
include Makefile_Eina.am
include Makefile_Eo.am
include Makefile_Eet.am
include Makefile_Evas.am
+include Makefile_Ecore.am
+include Makefile_Ecore_Con.am
+include Makefile_Ecore_Ipc.am
+include Makefile_Ecore_File.am
+include Makefile_Ecore_Input.am
+if HAVE_ECORE_COCOA
+include Makefile_Ecore_Cocoa.am
+endif
+if HAVE_ECORE_DIRECTFB
+include Makefile_Ecore_DirectFB.am
+endif
+if HAVE_ECORE_FB
+include Makefile_Ecore_FB.am
+endif
+if HAVE_PS3
+include Makefile_Ecore_Psl1ght.am
+endif
+if HAVE_ECORE_SDL
+include Makefile_Ecore_SDL.am
+endif
+if HAVE_ECORE_WAYLAND
+include Makefile_Ecore_Wayland.am
+endif
+if HAVE_WIN32
+include Makefile_Ecore_Win32.am
+endif
+if HAVE_WINCE
+include Makefile_Ecore_WinCE.am
+endif
+if HAVE_ECORE_X
+include Makefile_Ecore_X.am
+endif
+include Makefile_Ecore_Imf.am
include Makefile_Embryo.am
.PHONY: benchmark examples
diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
new file mode 100644
index 0000000000..eabe603558
--- /dev/null
+++ b/src/Makefile_Ecore.am
@@ -0,0 +1,88 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore/libecore.la
+
+installed_ecoremainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoremainheaders_DATA = \
+lib/ecore/Ecore.h \
+lib/ecore/Ecore_Getopt.h
+
+lib_ecore_libecore_la_SOURCES = \
+lib/ecore/ecore.c \
+lib/ecore/ecore_alloc.c \
+lib/ecore/ecore_anim.c \
+lib/ecore/ecore_app.c \
+lib/ecore/ecore_events.c \
+lib/ecore/ecore_getopt.c \
+lib/ecore/ecore_glib.c \
+lib/ecore/ecore_idle_enterer.c \
+lib/ecore/ecore_idle_exiter.c \
+lib/ecore/ecore_idler.c \
+lib/ecore/ecore_job.c \
+lib/ecore/ecore_main.c \
+lib/ecore/ecore_pipe.c \
+lib/ecore/ecore_poll.c \
+lib/ecore/ecore_time.c \
+lib/ecore/ecore_timer.c \
+lib/ecore/ecore_thread.c \
+lib/ecore/ecore_throttle.c \
+lib/ecore/ecore_private.h
+
+if HAVE_WIN32
+lib_ecore_libecore_la_SOURCES += lib/ecore/ecore_exe_win32.c
+else
+if HAVE_WINCE
+lib_ecore_libecore_la_SOURCES += lib/ecore/ecore_exe_wince.c
+else
+#if ECORE_HAVE_PS3
+#libecore_la_SOURCES += ecore_exe_ps3.c
+#else
+#if ECORE_HAVE_EXOTIC
+#libecore_la_SOURCES +=
+#else
+lib_ecore_libecore_la_SOURCES += lib/ecore/ecore_signal.c lib/ecore/ecore_exe.c
+#endif
+#endif
+endif
+endif
+
+lib_ecore_libecore_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-DEFL_ECORE_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_CFLAGS@
+
+if HAVE_WINDOWS
+lib_ecore_libecore_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/evil \
+-I$(top_builddir)/src/lib/evil
+endif
+
+if HAVE_PS3
+lib_ecore_libecore_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/escape \
+-I$(top_builddir)/src/lib/escape
+endif
+
+lib_ecore_libecore_la_LIBADD = \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+if HAVE_WINDOWS
+lib_ecore_libecore_la_LIBADD += lib/evil/libevil.la
+endif
+
+if HAVE_PS3
+lib_ecore_libecore_la_LIBADD += lib/escape/libescape.la
+endif
+
+lib_ecore_libecore_la_LIBADD += @ECORE_LIBS@ @EFL_COV_LIBS@ -lm
+
+lib_ecore_libecore_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Cocoa.am b/src/Makefile_Ecore_Cocoa.am
new file mode 100644
index 0000000000..f7f82918a1
--- /dev/null
+++ b/src/Makefile_Ecore_Cocoa.am
@@ -0,0 +1,37 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_cocoa/libecore_cocoa.la
+
+installed_ecorecocoamainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorecocoamainheaders_DATA = \
+lib/ecore_cocoa/Ecore_Cocoa.h \
+lib/ecore_cocoa/Ecore_Cocoa_Keys.h
+
+lib_ecore_cocoa_libecore_cocoa_la_SOURCES = \
+lib/ecore_cocoa/ecore_cocoa.m \
+lib/ecore_cocoa/ecore_cocoa_window.m \
+lib/ecore_cocoa/ecore_cocoa_private.h
+
+lib_ecore_cocoa_libecore_cocoa_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_cocoa \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_cocoa \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_cocoa_libecore_cocoa_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_COCOA_LIBS@
+
+lib_ecore_cocoa_libecore_cocoa_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
new file mode 100644
index 0000000000..f2e6ee8537
--- /dev/null
+++ b/src/Makefile_Ecore_Con.am
@@ -0,0 +1,70 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_con/libecore_con.la
+
+installed_ecoreconmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreconmainheaders_DATA = \
+lib/ecore_con/Ecore_Con.h \
+lib/ecore_con/Ecore_Con_Eet.h
+
+lib_ecore_con_libecore_con_la_SOURCES = \
+lib/ecore_con/ecore_con_alloc.c \
+lib/ecore_con/ecore_con.c \
+lib/ecore_con/ecore_con_eet.c \
+lib/ecore_con/ecore_con_socks.c \
+lib/ecore_con/ecore_con_ssl.c \
+lib/ecore_con/ecore_con_url.c \
+lib/ecore_con/ecore_con_private.h
+
+if HAVE_WINDOWS
+lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c
+else
+lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c
+endif
+
+if HAVE_CARES
+lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_ares.c
+else
+if HAVE_IPV6
+lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_dns.c lib/ecore_con/dns.c lib/ecore_con/dns.h
+else
+lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_info.c
+endif
+endif
+
+lib_ecore_con_libecore_con_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/eet \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_con \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/eet \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_con \
+-DEFL_ECORE_CON_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_CON_CFLAGS@
+
+if HAVE_WINDOWS
+lib_ecore_con_libecore_con_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/evil \
+-I$(top_builddir)/src/lib/evil
+endif
+
+lib_ecore_con_libecore_con_la_LIBADD = \
+lib/ecore/libecore.la \
+lib/eet/libeet.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+if HAVE_WINDOWS
+lib_ecore_con_libecore_con_la_LIBADD += lib/evil/libevil.la
+endif
+
+lib_ecore_con_libecore_con_la_LIBADD += @ECORE_CON_LIBS@ @EFL_COV_LIBS@ -lm
+
+lib_ecore_con_libecore_con_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_DirectFB.am b/src/Makefile_Ecore_DirectFB.am
new file mode 100644
index 0000000000..6e2d54c27a
--- /dev/null
+++ b/src/Makefile_Ecore_DirectFB.am
@@ -0,0 +1,34 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_directfb/libecore_directfb.la
+
+installed_ecoredirectfbmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoredirectfbmainheaders_DATA = \
+lib/ecore_directfb/Ecore_DirectFB.h
+
+lib_ecore_directfb_libecore_directfb_la_SOURCES = \
+lib/ecore_directfb/ecore_directfb.c \
+lib/ecore_directfb/ecore_directfb_keys.h \
+lib/ecore_directfb/ecore_directfb_private.h
+
+lib_ecore_directfb_libecore_directfb_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_directfb \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_directfb \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_DIRECTFB_CFLAGS@
+
+lib_ecore_directfb_libecore_directfb_la_LIBADD = \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_DIRECTFB_LIBS@
+
+lib_ecore_directfb_libecore_directfb_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Evas.am b/src/Makefile_Ecore_Evas.am
new file mode 100644
index 0000000000..595cd25f0f
--- /dev/null
+++ b/src/Makefile_Ecore_Evas.am
@@ -0,0 +1,160 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_evas/libecore_evas.la
+
+installed_ecoreevasmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreevasmainheaders_DATA = \
+lib/ecore_evas/Ecore_Evas.h
+
+lib_ecore_evas_libecore_evas_la_SOURCES = \
+lib/ecore_evas/ecore_evas.c \
+lib/ecore_evas/ecore_evas_util.c \
+lib/ecore_evas/ecore_evas_x.c \
+lib/ecore_evas/ecore_evas_fb.c \
+lib/ecore_evas/ecore_evas_buffer.c \
+lib/ecore_evas/ecore_evas_directfb.c \
+lib/ecore_evas/ecore_evas_win32.c \
+lib/ecore_evas/ecore_evas_sdl.c \
+lib/ecore_evas/ecore_evas_cocoa.c \
+lib/ecore_evas/ecore_evas_wince.c \
+lib/ecore_evas/ecore_evas_ews.c \
+lib/ecore_evas/ecore_evas_psl1ght.c \
+lib/ecore_evas/ecore_evas_wayland_shm.c \
+lib/ecore_evas/ecore_evas_wayland_egl.c \
+lib/ecore_evas/ecore_evas_extn.c \
+lib/ecore_evas/ecore_evas_private.h
+
+if BUILD_ECORE_WAYLAND
+lib_ecore_evas_libecore_evas_la_SOURCES += \
+lib/ecore_evas/ecore_evas_wayland_common.c
+endif
+
+lib_ecore_evas_libecore_evas_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_ipc \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_input_evas \
+-I$(top_srcdir)/src/lib/ecore_evas \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_ipc \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_input_evas \
+-I$(top_builddir)/src/lib/ecore_evas \
+-DEFL_ECORE_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+if BUILD_ECORE_COCOA
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_cocoa \
+-I$(top_builddir)/src/lib/ecore_cocoa
+endif
+
+if BUILD_ECORE_DIRECTFB
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_directfb \
+-I$(top_builddir)/src/lib/ecore_directfb
+endif
+
+if BUILD_ECORE_FB
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_fb \
+-I$(top_builddir)/src/lib/ecore_fb
+endif
+
+if BUILD_ECORE_PSL1GHT
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_psl1ght \
+-I$(top_builddir)/src/lib/ecore_psl1ght
+endif
+
+if BUILD_ECORE_SDL
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_sdl \
+-I$(top_builddir)/src/lib/ecore_sdl
+endif
+
+if BUILD_ECORE_WAYLAND
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_wayland \
+-I$(top_builddir)/src/lib/ecore_wayland
+endif
+
+if BUILD_ECORE_WIN32
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_win32 \
+-I$(top_builddir)/src/lib/ecore_win32
+endif
+
+if BUILD_ECORE_WINCE
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_wince \
+-I$(top_builddir)/src/lib/ecore_wince
+endif
+
+if BUILD_ECORE_X
+lib_ecore_evas_libecore_evas_la_CPPFLAGS += \
+-I$(top_srcdir)/src/lib/ecore_x \
+-I$(top_builddir)/src/lib/ecore_x
+endif
+
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_input_evas/libecore_input_evas.la \
+lib/ecore_input/libecore_input.la \
+lib/ecore_ipc/libecore_ipc.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_EVAS_LIBS@
+
+if BUILD_ECORE_COCOA
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_cocoa/libecore_cocoa.la
+endif
+
+if BUILD_ECORE_DIRECTFB
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_directfb/libecore_directfb.la
+endif
+
+if BUILD_ECORE_FB
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_fb/libecore_fb.la
+endif
+
+if BUILD_ECORE_PSL1GHT
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_psl1ght/libecore_psl1ght.la
+endif
+
+if BUILD_ECORE_SDL
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_sdl/libecore_sdl.la
+endif
+
+if BUILD_ECORE_WAYLAND
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_wayland/libecore_wayland.la
+endif
+
+if BUILD_ECORE_WIN32
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_win32/libecore_win32.la
+endif
+
+if BUILD_ECORE_WINCE
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_wince/libecore_wince.la
+endif
+
+if BUILD_ECORE_X
+lib_ecore_evas_libecore_evas_la_LIBADD = \
+lib/ecore_x/libecore_x.la
+endif
+
+lib_ecore_evas_libecore_evas_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_FB.am b/src/Makefile_Ecore_FB.am
new file mode 100644
index 0000000000..adcc5ebdc6
--- /dev/null
+++ b/src/Makefile_Ecore_FB.am
@@ -0,0 +1,42 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_fb/libecore_fb.la
+
+installed_ecorefbmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorefbmainheaders_DATA = \
+lib/ecore_fb/Ecore_Fb.h
+
+lib_ecore_fb_libecore_fb_la_SOURCES = \
+lib/ecore_fb/ecore_fb.c \
+lib/ecore_fb/ecore_fb_li.c \
+lib/ecore_fb/ecore_fb_ts.c \
+lib/ecore_fb/ecore_fb_vt.c \
+lib/ecore_fb/ecore_fb_keytable.h \
+lib/ecore_fb/ecore_fb_private.h
+# deprecated sources (might not compile):
+# lib/ecore_fb/ecore_fb_kbd.c
+# lib/ecore_fb/ecore_fb_ps2.c
+
+lib_ecore_fb_libecore_fb_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_fb \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_fb \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_FB_CFLAGS@
+
+lib_ecore_fb_libecore_fb_la_LIBADD = \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_FB_LIBS@
+
+lib_ecore_fb_libecore_fb_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_File.am b/src/Makefile_Ecore_File.am
new file mode 100644
index 0000000000..2172245342
--- /dev/null
+++ b/src/Makefile_Ecore_File.am
@@ -0,0 +1,41 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_file/libecore_file.la
+
+installed_ecorefilemainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorefilemainheaders_DATA = \
+lib/ecore_file/Ecore_File.h
+
+lib_ecore_file_libecore_file_la_SOURCES = \
+lib/ecore_file/ecore_file.c \
+lib/ecore_file/ecore_file_download.c \
+lib/ecore_file/ecore_file_monitor.c \
+lib/ecore_file/ecore_file_monitor_inotify.c \
+lib/ecore_file/ecore_file_monitor_poll.c \
+lib/ecore_file/ecore_file_monitor_win32.c \
+lib/ecore_file/ecore_file_path.c \
+lib/ecore_file/ecore_file_private.h
+
+lib_ecore_file_libecore_file_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_con \
+-I$(top_srcdir)/src/lib/ecore_file \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_con \
+-I$(top_builddir)/src/lib/ecore_file \
+-DEFL_ECORE_FILE_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_file_libecore_file_la_LIBADD = \
+lib/ecore_con/libecore_con.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_file_libecore_file_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Imf.am b/src/Makefile_Ecore_Imf.am
new file mode 100644
index 0000000000..820ae2b12a
--- /dev/null
+++ b/src/Makefile_Ecore_Imf.am
@@ -0,0 +1,186 @@
+
+### Library
+
+lib_LTLIBRARIES += \
+lib/ecore_imf/libecore_imf.la \
+lib/ecore_imf/libecore_imf_evas.la
+
+installed_ecoreimfmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreimfmainheaders_DATA = \
+lib/ecore_imf/Ecore_IMF.h
+
+lib_ecore_imf_libecore_imf_la_SOURCES = \
+lib/ecore_imf/ecore_imf.c \
+lib/ecore_imf/ecore_imf_context.c \
+lib/ecore_imf/ecore_imf_module.c \
+lib/ecore_imf/ecore_imf_private.h
+
+lib_ecore_imf_libecore_imf_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_imf \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_imf \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DEFL_ECORE_IMF_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_imf_libecore_imf_la_LIBADD = \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_imf_libecore_imf_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
+
+installed_ecoreimfevasmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreimfevasmainheaders_DATA = \
+lib/ecore_imf/Ecore_IMF_Evas.h
+
+lib_ecore_imf_libecore_imf_evas_la_SOURCES = \
+lib/ecore_imf/ecore_imf_evas.c
+
+lib_ecore_imf_libecore_imf_evas_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/evas \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_imf \
+-I$(top_srcdir)/src/lib/ecore_imf_evas \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/evas \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_imf \
+-I$(top_builddir)/src/lib/ecore_imf_evas \
+-DEFL_ECORE_IMF_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_imf_libecore_imf_evas_la_LIBADD = \
+lib/ecore_imf/libecore_imf.la \
+lib/ecore/libecore.la \
+lib/evas/libevas.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_imf_libecore_imf_evas_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
+
+
+### Modules
+
+# Ibus
+
+if BUILD_ECORE_IMF_IBUS
+ecoreimfibuspkgdir = $(libdir)/ecore/immodules
+ecoreimfibuspkg_LTLIBRARIES = modules/ecore/immodules/ibus/ibus.la
+modules_ecore_immodules_ibus_ibus_la_SOURCES = \
+modules/ecore/immodules/ibus/ibus_module.c \
+modules/ecore/immodules/ibus/ibus_imcontext.c \
+modules/ecore/immodules/ibus/ibus_imcontext.h
+modules_ecore_immodules_ibus_ibus_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_x \
+-I$(top_srcdir)/src/lib/ecore_imf \
+-I$(top_srcdir)/src/lib/ecore_evas \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_x \
+-I$(top_builddir)/src/lib/ecore_imf \
+-I$(top_builddir)/src/lib/ecore_evas \
+-DEFL_ECORE_IMF_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@IBUS_CFLAGS@
+modules_ecore_immodules_ibus_ibus_la_LIBADD = \
+lib/ecore_imf/libecore_evas.la \
+lib/ecore_imf/libecore_imf.la \
+lib/ecore_x/libecore_x.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@IBUS_LIBS@
+modules_ecore_immodules_ibus_ibus_la_LDFLAGS = -no-undefined -module -avoid-version
+modules_ecore_immodules_ibus_ibus_la_LIBTOOLFLAGS = --tag=disable-static
+endif
+
+# Scim
+
+if BUILD_ECORE_IMF_SCIM
+ecoreimfscimpkgdir = $(libdir)/ecore/immodules
+ecoreimfscimpkg_LTLIBRARIES = modules/ecore/immodules/scim/scim.la
+modules_ecore_immodules_scim_scim_la_SOURCES = \
+modules/ecore/immodules/scim/scim_module.cpp \
+modules/ecore/immodules/scim/scim_imcontext.cpp \
+modules/ecore/immodules/scim/scim_imcontext.h
+modules_ecore_immodules_scim_scim_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_x \
+-I$(top_srcdir)/src/lib/ecore_imf \
+-I$(top_srcdir)/src/lib/ecore_evas \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_x \
+-I$(top_builddir)/src/lib/ecore_imf \
+-I$(top_builddir)/src/lib/ecore_evas \
+-DEFL_ECORE_IMF_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@SCIM_CFLAGS@
+modules_ecore_immodules_scim_scim_la_LIBADD = \
+lib/ecore_imf/libecore_evas.la \
+lib/ecore_imf/libecore_imf.la \
+lib/ecore_x/libecore_x.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@SCIM_LIBS@
+modules_ecore_immodules_scim_scim_la_LDFLAGS = -no-undefined -module -avoid-version
+modules_ecore_immodules_scim_scim_la_LIBTOOLFLAGS = --tag=disable-static
+endif
+
+# Xim
+
+if BUILD_ECORE_IMF_XIM
+ecoreimfximpkgdir = $(libdir)/ecore/immodules
+ecoreimfximpkg_LTLIBRARIES = modules/ecore/immodules/xim/xim.la
+modules_ecore_immodules_xim_xim_la_SOURCES = \
+modules/ecore/immodules/xim/ecore_imf_xim.c
+modules_ecore_immodules_xim_xim_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_x \
+-I$(top_srcdir)/src/lib/ecore_imf \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_x \
+-I$(top_builddir)/src/lib/ecore_imf \
+-DEFL_ECORE_IMF_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+modules_ecore_immodules_xim_xim_la_LIBADD = \
+lib/ecore_imf/libecore_imf.la \
+lib/ecore_x/libecore_x.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+modules_ecore_immodules_xim_xim_la_LDFLAGS = -no-undefined -module -avoid-version
+modules_ecore_immodules_xim_xim_la_LIBTOOLFLAGS = --tag=disable-static
+endif
diff --git a/src/Makefile_Ecore_Input.am b/src/Makefile_Ecore_Input.am
new file mode 100644
index 0000000000..29aa449f45
--- /dev/null
+++ b/src/Makefile_Ecore_Input.am
@@ -0,0 +1,70 @@
+
+### Library
+
+lib_LTLIBRARIES += \
+lib/ecore_input/libecore_input.la \
+lib/ecore_input/libecore_input_evas.la
+
+installed_ecoreinputmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreinputmainheaders_DATA = \
+lib/ecore_input/Ecore_Input.h
+
+lib_ecore_input_libecore_input_la_SOURCES = \
+lib/ecore_input/ecore_input.c \
+lib/ecore_input/ecore_input_compose.c \
+lib/ecore_input/ecore_input_compose.h \
+lib/ecore_input/ecore_input_private.h
+
+lib_ecore_input_libecore_input_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-DEFL_ECORE_INPUT_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_input_libecore_input_la_LIBADD = \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_input_libecore_input_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
+
+installed_ecoreinputevasmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreinputevasmainheaders_DATA = \
+lib/ecore_input/Ecore_Input_Evas.h
+
+lib_ecore_input_libecore_input_evas_la_SOURCES = \
+lib/ecore_input/ecore_input_evas.c \
+lib/ecore_input/ecore_input_evas_private.h
+
+lib_ecore_input_libecore_input_evas_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/evas \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_input_evas \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/evas \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_input_evas \
+-DEFL_ECORE_INPUT_EVAS_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_input_libecore_input_evas_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/evas/libevas.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_input_libecore_input_evas_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Ipc.am b/src/Makefile_Ecore_Ipc.am
new file mode 100644
index 0000000000..ba09f374b7
--- /dev/null
+++ b/src/Makefile_Ecore_Ipc.am
@@ -0,0 +1,37 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_ipc/libecore_ipc.la
+
+installed_ecoreipcmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoreipcmainheaders_DATA = \
+lib/ecore_ipc/Ecore_Ipc.h
+
+lib_ecore_ipc_libecore_ipc_la_SOURCES = \
+lib/ecore_ipc/ecore_ipc.c \
+lib/ecore_ipc/ecore_ipc_private.h
+
+lib_ecore_ipc_libecore_ipc_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_con \
+-I$(top_srcdir)/src/lib/ecore_ipc \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_con \
+-I$(top_builddir)/src/lib/ecore_ipc \
+-DEFL_ECORE_IPC_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_ipc_libecore_ipc_la_LIBADD = \
+lib/ecore_con/libecore_con.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_ipc_libecore_ipc_la_LIBADD += @EFL_COV_LIBS@ -lm
+
+lib_ecore_ipc_libecore_ipc_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Psl1ght.am b/src/Makefile_Ecore_Psl1ght.am
new file mode 100644
index 0000000000..9ac146c63d
--- /dev/null
+++ b/src/Makefile_Ecore_Psl1ght.am
@@ -0,0 +1,38 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_psl1ght/libecore_psl1ght.la
+
+installed_ecorepsl1ghtmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorepsl1ghtmainheaders_DATA = \
+lib/ecore_psl1ght/Ecore_Psl1ght.h
+
+lib_ecore_psl1ght_libecore_psl1ght_la_SOURCES = \
+lib/ecore_psl1ght/ecore_psl1ght.c \
+lib/ecore_psl1ght/moveutil.c \
+lib/ecore_psl1ght/spursutil.c \
+lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h \
+lib/ecore_psl1ght/ecore_psl1ght_private.h
+
+lib_ecore_psl1ght_libecore_psl1ght_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_psl1ght \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_psl1ght \
+-DEFL_ECORE_PSL1GHT_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_psl1ght_libecore_psl1ght_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la
+
+lib_ecore_psl1ght_libecore_psl1ght_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_SDL.am b/src/Makefile_Ecore_SDL.am
new file mode 100644
index 0000000000..62e7a10266
--- /dev/null
+++ b/src/Makefile_Ecore_SDL.am
@@ -0,0 +1,38 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_sdl/libecore_sdl.la
+
+installed_ecoresdlmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecoresdlmainheaders_DATA = \
+lib/ecore_sdl/Ecore_Sdl.h
+
+lib_ecore_sdl_libecore_sdl_la_SOURCES = \
+lib/ecore_sdl/ecore_sdl.c \
+lib/ecore_sdl/Ecore_Sdl_Keys.h \
+lib/ecore_sdl/ecore_sdl_private.h
+
+lib_ecore_sdl_libecore_sdl_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_sdl \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_sdl \
+-DEFL_ECORE_SDL_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_SDL_CFLAGS@
+
+lib_ecore_sdl_libecore_sdl_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_SDL_LIBS@
+
+lib_ecore_sdl_libecore_sdl_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Wayland.am b/src/Makefile_Ecore_Wayland.am
new file mode 100644
index 0000000000..4923a1abf4
--- /dev/null
+++ b/src/Makefile_Ecore_Wayland.am
@@ -0,0 +1,40 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_wayland/libecore_wayland.la
+
+installed_ecorewaylandmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorewaylandmainheaders_DATA = \
+lib/ecore_wayland/Ecore_Wayland.h
+
+lib_ecore_wayland_libecore_wayland_la_SOURCES = \
+lib/ecore_wayland/ecore_wayland.c \
+lib/ecore_wayland/ecore_wl_dnd.c \
+lib/ecore_wayland/ecore_wl_input.c \
+lib/ecore_wayland/ecore_wl_output.c \
+lib/ecore_wayland/ecore_wl_window.c \
+lib/ecore_wayland/ecore_wayland_private.h
+
+lib_ecore_wayland_libecore_wayland_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_wayland \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_wayland \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_WAYLAND_CFLAGS@
+
+lib_ecore_wayland_libecore_wayland_la_LIBADD = \
+lib/ecore/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_WAYLAND_LIBS@
+
+lib_ecore_wayland_libecore_wayland_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_Win32.am b/src/Makefile_Ecore_Win32.am
new file mode 100644
index 0000000000..2491ca5aa7
--- /dev/null
+++ b/src/Makefile_Ecore_Win32.am
@@ -0,0 +1,51 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_win32/libecore_win32.la
+
+installed_ecorewin32mainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorewin32mainheaders_DATA = \
+lib/ecore_win32/Ecore_Win32.h
+
+lib_ecore_win32_libecore_win32_la_SOURCES = \
+lib/ecore_win32/ecore_win32.c \
+lib/ecore_win32/ecore_win32_cursor.c \
+lib/ecore_win32/ecore_win32_dnd.c \
+lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp \
+lib/ecore_win32/ecore_win32_dnd_data_object.cpp \
+lib/ecore_win32/ecore_win32_dnd_drop_source.cpp \
+lib/ecore_win32/ecore_win32_dnd_drop_target.cpp \
+lib/ecore_win32/ecore_win32_event.c \
+lib/ecore_win32/ecore_win32_window.c \
+lib/ecore_win32/ecore_win32_private.h \
+lib/ecore_win32/ecore_win32_dnd_enumformatetc.h \
+lib/ecore_win32/ecore_win32_dnd_data_object.h \
+lib/ecore_win32/ecore_win32_dnd_drop_source.h \
+lib/ecore_win32/ecore_win32_dnd_drop_target.h
+
+lib_ecore_win32_libecore_win32_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/evil \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_win32 \
+-I$(top_builddir)/src/lib/evil \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_win32 \
+-DEFL_ECORE_WIN32_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_win32_libecore_win32_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+lib/evil/libevil.la \
+@ECORE_WIN32_LIBS@
+
+lib_ecore_win32_libecore_win32_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_WinCE.am b/src/Makefile_Ecore_WinCE.am
new file mode 100644
index 0000000000..29122ab8c0
--- /dev/null
+++ b/src/Makefile_Ecore_WinCE.am
@@ -0,0 +1,41 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_wince/libecore_wince.la
+
+installed_ecorewincemainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorewincemainheaders_DATA = \
+lib/ecore_wince/Ecore_Wince.h
+
+lib_ecore_wince_libecore_wince_la_SOURCES = \
+lib/ecore_wince/ecore_wince.c \
+lib/ecore_wince/ecore_wince_event.c \
+lib/ecore_wince/ecore_wince_window.c \
+lib/ecore_wince/ecore_wince_private.h
+
+lib_ecore_wince_libecore_wince_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/evil \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_wince \
+-I$(top_builddir)/src/lib/evil \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_wince \
+-DEFL_ECORE_WINCE_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@
+
+lib_ecore_wince_libecore_wince_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+lib/evil/libevil.la \
+@ECORE_WINCE_LIBS@
+
+lib_ecore_wince_libecore_wince_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/Makefile_Ecore_X.am b/src/Makefile_Ecore_X.am
new file mode 100644
index 0000000000..cda857bd59
--- /dev/null
+++ b/src/Makefile_Ecore_X.am
@@ -0,0 +1,126 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_x/libecore_x.la
+
+installed_ecorexmainheadersdir = $(includedir)/ecore-@VMAJ@
+dist_installed_ecorexmainheaders_DATA = \
+lib/ecore_x/Ecore_X.h \
+lib/ecore_x/Ecore_X_Atoms.h \
+lib/ecore_x/Ecore_X_Cursor.h
+
+if HAVE_ECORE_X_XCB
+lib_ecore_x_libecore_x_la_SOURCES = \
+lib/ecore_x/xcb/ecore_xcb.c \
+lib/ecore_x/xcb/ecore_xcb_atoms.c \
+lib/ecore_x/xcb/ecore_xcb_extensions.c \
+lib/ecore_x/xcb/ecore_xcb_shape.c \
+lib/ecore_x/xcb/ecore_xcb_screensaver.c \
+lib/ecore_x/xcb/ecore_xcb_sync.c \
+lib/ecore_x/xcb/ecore_xcb_render.c \
+lib/ecore_x/xcb/ecore_xcb_randr.c \
+lib/ecore_x/xcb/ecore_xcb_xfixes.c \
+lib/ecore_x/xcb/ecore_xcb_composite.c \
+lib/ecore_x/xcb/ecore_xcb_cursor.c \
+lib/ecore_x/xcb/ecore_xcb_damage.c \
+lib/ecore_x/xcb/ecore_xcb_dnd.c \
+lib/ecore_x/xcb/ecore_xcb_dpms.c \
+lib/ecore_x/xcb/ecore_xcb_drawable.c \
+lib/ecore_x/xcb/ecore_xcb_e.c \
+lib/ecore_x/xcb/ecore_xcb_gc.c \
+lib/ecore_x/xcb/ecore_xcb_image.c \
+lib/ecore_x/xcb/ecore_xcb_input.c \
+lib/ecore_x/xcb/ecore_xcb_gesture.c \
+lib/ecore_x/xcb/ecore_xcb_mwm.c \
+lib/ecore_x/xcb/ecore_xcb_pixmap.c \
+lib/ecore_x/xcb/ecore_xcb_region.c \
+lib/ecore_x/xcb/ecore_xcb_selection.c \
+lib/ecore_x/xcb/ecore_xcb_textlist.c \
+lib/ecore_x/xcb/ecore_xcb_events.c \
+lib/ecore_x/xcb/ecore_xcb_keymap.c \
+lib/ecore_x/xcb/ecore_xcb_netwm.c \
+lib/ecore_x/xcb/ecore_xcb_icccm.c \
+lib/ecore_x/xcb/ecore_xcb_window.c \
+lib/ecore_x/xcb/ecore_xcb_window_prop.c \
+lib/ecore_x/xcb/ecore_xcb_window_shape.c \
+lib/ecore_x/xcb/ecore_xcb_window_shadow.c \
+lib/ecore_x/xcb/ecore_xcb_xinerama.c \
+lib/ecore_x/xcb/ecore_xcb_error.c \
+lib/ecore_x/xcb/ecore_xcb_xtest.c \
+lib/ecore_x/xcb/ecore_xcb_vsync.c \
+lib/ecore_x/xcb/ecore_xcb_xdefaults.c \
+lib/ecore_x/xcb/ecore_xcb_private.h
+else
+lib_ecore_x_libecore_x_la_SOURCES = \
+lib/ecore_x/xlib/ecore_x.c \
+lib/ecore_x/xlib/ecore_x_dnd.c \
+lib/ecore_x/xlib/ecore_x_sync.c \
+lib/ecore_x/xlib/ecore_x_randr.c \
+lib/ecore_x/xlib/ecore_x_randr_11.c \
+lib/ecore_x/xlib/ecore_x_randr_12.c \
+lib/ecore_x/xlib/ecore_x_randr_12_edid.c \
+lib/ecore_x/xlib/ecore_x_randr_13.c \
+lib/ecore_x/xlib/ecore_x_fixes.c \
+lib/ecore_x/xlib/ecore_x_damage.c \
+lib/ecore_x/xlib/ecore_x_composite.c \
+lib/ecore_x/xlib/ecore_x_error.c \
+lib/ecore_x/xlib/ecore_x_events.c \
+lib/ecore_x/xlib/ecore_x_icccm.c \
+lib/ecore_x/xlib/ecore_x_netwm.c \
+lib/ecore_x/xlib/ecore_x_mwm.c \
+lib/ecore_x/xlib/ecore_x_e.c \
+lib/ecore_x/xlib/ecore_x_selection.c \
+lib/ecore_x/xlib/ecore_x_window.c \
+lib/ecore_x/xlib/ecore_x_window_prop.c \
+lib/ecore_x/xlib/ecore_x_window_shape.c \
+lib/ecore_x/xlib/ecore_x_pixmap.c \
+lib/ecore_x/xlib/ecore_x_gc.c \
+lib/ecore_x/xlib/ecore_x_xinerama.c \
+lib/ecore_x/xlib/ecore_x_screensaver.c \
+lib/ecore_x/xlib/ecore_x_dpms.c \
+lib/ecore_x/xlib/ecore_x_drawable.c \
+lib/ecore_x/xlib/ecore_x_cursor.c \
+lib/ecore_x/xlib/ecore_x_test.c \
+lib/ecore_x/xlib/ecore_x_atoms.c \
+lib/ecore_x/xlib/ecore_x_region.c \
+lib/ecore_x/xlib/ecore_x_image.c \
+lib/ecore_x/xlib/ecore_x_xi2.c \
+lib/ecore_x/xlib/ecore_x_vsync.c \
+lib/ecore_x/xlib/ecore_x_randr.h \
+lib/ecore_x/xlib/ecore_x_gesture.c \
+lib/ecore_x/xlib/ecore_x_private.h
+endif
+
+lib_ecore_x_libecore_x_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/eina \
+-I$(top_srcdir)/src/lib/eo \
+-I$(top_srcdir)/src/lib/ecore \
+-I$(top_srcdir)/src/lib/ecore_input \
+-I$(top_srcdir)/src/lib/ecore_x \
+-I$(top_builddir)/src/lib/eina \
+-I$(top_builddir)/src/lib/eo \
+-I$(top_builddir)/src/lib/ecore \
+-I$(top_builddir)/src/lib/ecore_input \
+-I$(top_builddir)/src/lib/ecore_x \
+-DEFL_ECORE_X_BUILD \
+@EFL_CFLAGS@ \
+@EFL_COV_CFLAGS@ \
+@ECORE_X_CFLAGS@
+
+lib_ecore_x_libecore_x_la_LIBADD = \
+lib/ecore_input/libecore_input.la \
+lib/ecore/libecore.la \
+lib/eo/libeo.la \
+lib/eina/libeina.la \
+@ECORE_X_LIBS@
+
+lib_ecore_x_libecore_x_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
+
+### Utils
+
+noinst_PROGRAMS = utils/ecore/makekeys
+
+utils_ecore_makekeys_SOURCES = utils/ecore/makekeys.c
+
+EXTRA_DIST += utils/ecore/mkks.sh
+
diff --git a/src/Makefile_Escape.am b/src/Makefile_Escape.am
new file mode 100644
index 0000000000..d237d184a2
--- /dev/null
+++ b/src/Makefile_Escape.am
@@ -0,0 +1,25 @@
+
+### Library
+
+lib_LTLIBRARIES += lib/escape/libescape.la
+
+install_escapeheadersdir = $(includedir)/escape-@VMAJ@
+dist_install_escapeheaders_DATA = \
+lib/escape/Escape.h \
+lib/escape/escape_libgen.h \
+lib/escape/escape_unistd.h
+
+escapemmanheadersdir = $(includedir)/escape-@VMAJ@/sys
+dist_escapemmanheaders_DATA = \
+lib/escape/sys/mman.h
+
+lib_escape_libescape_la_SOURCES = \
+lib/escape/escape_libgen.c \
+lib/escape/escape_mman.c \
+lib/escape/escape_unistd.c
+
+lib_escape_libescape_la_CPPFLAGS = \
+-I$(top_srcdir)/src/lib/escape \
+-I$(top_builddir)/src/lib/escape
+lib_escape_libescape_la_LIBADD = @ESCAPE_LIBS@
+lib_escape_libescape_la_LDFLAGS = -no-undefined -version-info @version_info@
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 616c466b4e..62b86c0f14 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -439,70 +439,6 @@ modules_evas_engines_buffer_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
endif
-if BUILD_ENGINE_DIRECT3D
-dist_installed_evasmainheaders_DATA += modules/evas/engines/direct3d/Evas_Engine_Direct3D.h
-DIRECT3D_SOURCES = \
-modules/evas/engines/direct3d/evas_engine.c \
-modules/evas/engines/direct3d/evas_direct3d_context.cpp \
-modules/evas/engines/direct3d/evas_direct3d_device.cpp \
-modules/evas/engines/direct3d/evas_direct3d_image_cache.cpp \
-modules/evas/engines/direct3d/evas_direct3d_main.cpp \
-modules/evas/engines/direct3d/evas_direct3d_object.cpp \
-modules/evas/engines/direct3d/evas_direct3d_object_font.cpp \
-modules/evas/engines/direct3d/evas_direct3d_object_image.cpp \
-modules/evas/engines/direct3d/evas_direct3d_object_line.cpp \
-modules/evas/engines/direct3d/evas_direct3d_object_rect.cpp \
-modules/evas/engines/direct3d/evas_direct3d_scene.cpp \
-modules/evas/engines/direct3d/evas_direct3d_shader_pack.cpp \
-modules/evas/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp \
-modules/evas/engines/direct3d/array.h \
-modules/evas/engines/direct3d/evas_direct3d_context.h \
-modules/evas/engines/direct3d/evas_direct3d_device.h \
-modules/evas/engines/direct3d/evas_direct3d_image_cache.h \
-modules/evas/engines/direct3d/evas_direct3d_object.h \
-modules/evas/engines/direct3d/evas_direct3d_object_font.h \
-modules/evas/engines/direct3d/evas_direct3d_object_image.h \
-modules/evas/engines/direct3d/evas_direct3d_object_line.h \
-modules/evas/engines/direct3d/evas_direct3d_object_rect.h \
-modules/evas/engines/direct3d/evas_direct3d_scene.h \
-modules/evas/engines/direct3d/evas_direct3d_shader_pack.h \
-modules/evas/engines/direct3d/evas_direct3d_vertex_buffer_cache.h \
-modules/evas/engines/direct3d/evas_engine.h \
-modules/evas/engines/direct3d/ref.h
-if EVAS_STATIC_BUILD_DIRECT3D
-lib_evas_libevas_la_SOURCES += $(DIRECT3D_SOURCES)
-lib_evas_libevas_la_CPPFLAGS += @evas_engine_direct3d_cflags@
-lib_evas_libevas_la_CXXFLAGS += -fno-rtti -fno-exceptions
-lib_evas_libevas_la_LIBADD += @evas_engine_direct3d_libs@
-else
-enginedirect3dpkgdir = $(libdir)/evas/modules/engines/direct3d/$(MODULE_ARCH)
-enginedirect3dpkg_LTLIBRARIES = modules/evas/engines/direct3d/module.la
-modules_evas_engines_direct3d_module_la_SOURCES = $(DIRECT3D_SOURCES)
-modules_evas_engines_direct3d_module_la_CPPFLAGS = \
--I$(top_srcdir)/src/lib/eina \
--I$(top_builddir)/src/lib/eina \
--I$(top_srcdir)/src/lib/eo \
--I$(top_builddir)/src/lib/eo \
--I$(top_srcdir)/src/lib/evas \
--I$(top_builddir)/src/lib/evas \
--I$(top_srcdir)/src/lib/evas/include \
--I$(top_builddir)/src/lib/evas/include \
--I$(top_srcdir)/src/lib/evas/cserve2 \
--I$(top_builddir)/src/lib/evas/cserve2 \
--DEFL_EVAS_BUILD \
-@evas_engine_direct3d_cflags@ \
-@EFL_CFLAGS@ \
-@EVAS_CFLAGS@
-modules_evas_engines_direct3d_module_la_CXXFLAGS = -fno-rtti -fno-exceptions
-modules_evas_engines_direct3d_module_la_LIBADD = \
-lib/evas/libevas.la \
-@EFL_LIBS@ \
-@evas_engine_direct3d_libs@
-modules_evas_engines_direct3d_module_la_LDFLAGS = -no-undefined -module -avoid-version
-modules_evas_engines_direct3d_module_la_LIBTOOLFLAGS = --tag=disable-static
-endif
-endif
-
if BUILD_ENGINE_DIRECTFB
dist_installed_evasmainheaders_DATA += modules/evas/engines/directfb/Evas_Engine_DirectFB.h
DIRECTFB_SOURCES = \
diff --git a/src/lib/ecore/Ecore.h b/src/lib/ecore/Ecore.h
new file mode 100644
index 0000000000..5a02211526
--- /dev/null
+++ b/src/lib/ecore/Ecore.h
@@ -0,0 +1,2954 @@
+/**
+ @brief Ecore Library Public API Calls
+
+ These routines are used for Ecore Library interaction
+ */
+
+/**
+
+ @mainpage Ecore
+
+ @version 1.7
+ @date 2000-2012
+
+ Please see the @ref authors page for contact details.
+
+ @section intro Introduction
+
+ Ecore is a library of convenience functions. A brief explanation of how to use
+ it can be found in @ref Ecore_Main_Loop_Page.
+
+ The Ecore library provides the following modules:
+ @li @ref Ecore_Main_Loop_Group
+ @li @ref Ecore_File_Group
+ @li @ref Ecore_Con_Group
+ @li @ref Ecore_Evas_Group
+ @li @ref Ecore_FB_Group
+ @li @ref Ecore_IMF_Lib_Group
+ @li @ref Ecore_IMF_Context_Group
+ @li @ref Ecore_IMF_Context_Module_Group
+ @li @ref Ecore_IMF_Evas_Group
+ @li @link Ecore_Ipc.h Ecore_IPC - Inter Process Communication functions. @endlink
+ @li @link Ecore_X.h Ecore_X - X Windows System wrapper. @endlink
+ @li @ref Ecore_Win32_Group
+ @li @ref Ecore_WinCE_Group
+
+ For more info on Ecore usage, there are these @ref Examples.
+
+ @section compiling How to compile using Ecore?
+ pkgconfig (.pc) files are installed for every ecore module.
+ Thus, to compile using any of them, you can use something like the following:
+
+@verbatim
+gcc *.c $(pkg-config ecore ecore-$x ecore-$y [...] --cflags --libs)
+@endverbatim
+
+ @section install How is it installed?
+
+ Suggested configure options for ecore for a Linux desktop X display
+ with OpenGL and Software support, communication (networking) and
+ IPC (inter process communication):
+
+@verbatim
+./configure \
+ --enable-ecore-con \
+ --enable-ecore-ipc \
+ --enable-ecore-file \
+ --enable-ecore-input \
+ --enable-ecore-input-evas \
+ --enable-ecore-x \
+ --enable-ecore-evas \
+ --enable-ecore-evas-software-buffer \
+ --enable-ecore-evas-software-x11 \
+ --enable-ecore-evas-opengl-x11
+make
+sudo make install
+@endverbatim
+
+ */
+
+/**
+ @page authors Authors
+ @author Carsten Haitzler <raster@rasterman.com>
+ @author Tom Gilbert <tom@linuxbrit.co.uk>
+ @author Burra <burra@colorado.edu>
+ @author Chris Ross <chris@darkrock.co.uk>
+ @author Term <term@twistedpath.org>
+ @author Tilman Sauerbeck <tilman@code-monkey.de>
+ @author Ibukun Olumuyiwa <ibukun@computer.org>
+ @author Yuri <da2001@hotmail.ru>
+ @author Nicholas Curran <quasar@bigblue.net.au>
+ @author Howell Tam <pigeon@pigeond.net>
+ @author Nathan Ingersoll <rbdpngn@users.sourceforge.net>
+ @author Andrew Elcock <andy@elcock.org>
+ @author Kim Woelders <kim@woelders.dk>
+ @author Sebastian Dransfeld <sebastid@tango.flipp.net>
+ @author Simon Poole <simon.armlinux@themalago.net>
+ @author Jorge Luis Zapata Muga <jorgeluis.zapata@gmail.com>
+ @author dan sinclair <zero@everburning.com>
+ @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
+ @author David 'onefang' Seikel <onefang@gmail.com>
+ @author Hisham 'CodeWarrior' Mardam Bey <hisham@hisham.cc>
+ @author Brian 'rephorm' Mattern <rephorm@rephorm.com>
+ @author Tim Horton <hortont424@gmail.com>
+ @author Arnaud de Turckheim 'quarium' <quarium@gmail.com>
+ @author Matt Barclay <mbarclay@gmail.com>
+ @author Peter Wehrfritz <peter.wehrfritz@web.de>
+ @author Albin "Lutin" Tonnerre <albin.tonnerre@gmail.com>
+ @author Vincent Torri <vincent.torri@gmail.com>
+ @author Lars Munch <lars@segv.dk>
+ @author Andre Dieb <andre.dieb@gmail.com>
+ @author Mathieu Taillefumier <mathieu.taillefumier@free.fr>
+ @author Rui Miguel Silva Seabra <rms@1407.org>
+ @author Samsung Electronics
+ @author Samsung SAIT
+ @author Nicolas Aguirre <aguirre.nicolas@gmail.com>
+ @author Brett Nash <nash@nash.id.au>
+ @author Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
+ @author Leif Middelschulte <leif.middelschulte@gmail.com>
+ @author Mike McCormack <mj.mccormack@samsung.com>
+ @author Sangho Park <gouache95@gmail.com>
+ @author Jihoon Kim <jihoon48.kim@samsung.com> <imfine98@gmail.com>
+ @author PnB <Poor.NewBie@gmail.com>
+ @author Daniel Juyung Seo <seojuyung2@gmail.com> <juyung.seo@samsung.com>
+ @author Christopher 'devilhorns' Michael <cpmichael1@comcast.net>
+ @author ChunEon Park <hermet@hermet.pe.kr>
+ @author xlopez@igalia.com
+ @author Rafael Antognolli <antognolli@profusion.mobi>
+ @author Kim Yunhan <spbear@gmail.com>
+ @author Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ @author Bluezery <ohpowel@gmail.com>
+ @author Doyoun Kang <wayofmine@gmail.com> <doyoun.kang@samsung.com>
+ @author Haifeng Deng <haifeng.deng@samsung.com>
+ @author Jérémy Zurcher <jeremy@asynk.ch>
+ @author Vikram Narayanan <vikram186@gmail.com>
+
+ Please contact <enlightenment-devel@lists.sourceforge.net> to get in
+ contact with the developers and maintainers.
+ */
+
+/**
+ * @page Ecore_Main_Loop_Page The Ecore Main Loop
+ *
+ * @section intro What is Ecore?
+ *
+ * Ecore is a clean and tiny event loop library with many modules to do lots of
+ * convenient things for a programmer, to save time and effort. It's small and
+ * lean, designed to work from embedded systems all the way up to large and
+ * powerful multi-cpu workstations. The main loop has a number of primitives to
+ * be used with its main loop. It serializes all the primitives and allows for
+ * great responsiveness without the need for threads(or any other concurrency).
+ *
+ * @subsection timers Timers
+ *
+ * Timers serve two main purposes: doing something at a specified time and
+ * repeatedly doing something with a set interval.
+ * @see Ecore_Timer_Group
+ *
+ * @subsection pollers Pollers
+ *
+ * Pollers allow for polling to be centralized into a single place therefore
+ * alleviating the need for different parts of the program to wake up at
+ * different times to do polling, thereby making the code simpler and more
+ * efficient.
+ * @see Ecore_Poller_Group
+ *
+ * @subsection idler Idlers
+ *
+ * There are three types of idlers, enterers, idlers(proper) and exiters, they
+ * are called, respectively, when the program is about to enter an idle state,
+ * when the program is idle and when the program is leaving an idle state. Idler
+ * enterers are usually a good place to update the program state. Proper idlers
+ * are the appropriate place to do heavy computational tasks thereby using what
+ * would otherwise be wasted CPU cycles. Exiters are the perfect place to do
+ * anything your program should do just before processing events(also timers,
+ * poolers, file descriptor handlers and animators)
+ * @see Ecore_Idle_Group
+ *
+ * @subsection fd_handler File descriptor handlers
+ *
+ * File descriptor handlers allow you to monitor when there is data available to
+ * read on file descriptors, when writing will not block or if there was an
+ * error. Any valid file descriptor can be used with this API, regardless of if
+ * was gotten with an OS specific API or from ecore.
+ * @see Ecore_FD_Handler_Group
+ *
+ * @subsection animators Animators
+ *
+ * Ecore provides a facility called animators, so named since the intended use
+ * was in animations, that facilitates knowing what percentage of a given
+ * interval has elapsed. This is perfect for performing animations, but is not
+ * limited to that use, it can, for example, also be used to create a progress
+ * bar.
+ * @see Ecore_Animator_Group
+ *
+ * @subsection ev_handlers Event handlers
+ *
+ * Event handlers are, arguably, the most important feature of the ecore main
+ * loop, they are what allows the programmer to easily handle user interaction.
+ * Events however are not only things the user does, events can represent
+ * anything for which a type is created.
+ * @see Ecore_Event_Group
+ *
+ * All of these primitives are discussed in more detail in their respective
+ * pages linked above.
+ *
+ * Here is a diagram of the main loop flow of a simple program:
+ *
+ * @image html prog_flow.png
+ * @image latex prog_flow.eps width=\textwidth
+ *
+ *
+ *
+ * @section work How does Ecore work?
+ *
+ * Ecore is very easy to learn and use. All the function calls are designed to
+ * be easy to remember, explicit in describing what they do, and heavily
+ * name-spaced. Ecore programs can start and be very simple.
+ *
+ * For example:
+ *
+ * @code
+ * #include <Ecore.h>
+ *
+ * int
+ * main(int argc, const char **argv)
+ * {
+ * ecore_init();
+ * ecore_app_args_set(argc, argv);
+ * ecore_main_loop_begin();
+ * ecore_shutdown();
+ * return 0;
+ * }
+ * @endcode
+ *
+ * This program is very simple and doesn't check for errors, but it does start up
+ * and begin a main loop waiting for events or timers to tick off. This program
+ * doesn't set up any, but now we can expand on this simple program a little
+ * more by adding some event handlers and timers.
+ *
+ * @code
+ * #include <Ecore.h>
+ *
+ * Ecore_Timer *timer1 = NULL;
+ * Ecore_Event_Handler *handler1 = NULL;
+ * double start_time = 0.0;
+ *
+ * int
+ * timer_func(void *data)
+ * {
+ * printf("Tick timer. Sec: %3.2f\n", ecore_time_get() - start_time);
+ * return 1;
+ * }
+ *
+ * int
+ * exit_func(void *data, int ev_type, void *ev)
+ * {
+ * Ecore_Event_Signal_Exit *e;
+ *
+ * e = (Ecore_Event_Signal_Exit *)ev;
+ * if (e->interrupt) printf("Exit: interrupt\n");
+ * else if (e->quit) printf("Exit: quit\n");
+ * else if (e->terminate) printf("Exit: terminate\n");
+ * ecore_main_loop_quit();
+ * return 1;
+ * }
+ *
+ * int
+ * main(int argc, const char **argv)
+ * {
+ * ecore_init();
+ * ecore_app_args_set(argc, argv);
+ * start_time = ecore_time_get();
+ * handler1 = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, exit_func, NULL);
+ * timer1 = ecore_timer_add(0.5, timer_func, NULL);
+ * ecore_main_loop_begin();
+ * ecore_shutdown();
+ * return 0;
+ * }
+ * @endcode
+ *
+ * In the previous example, we initialize our application and get the time at
+ * which our program has started so we can calculate an offset. We set
+ * up a timer to tick off in 0.5 seconds, and since it returns 1, will
+ * keep ticking off every 0.5 seconds until it returns 0, or is deleted
+ * by hand. An event handler is set up to call a function -
+ * exit_func(),
+ * whenever an event of type ECORE_EVENT_SIGNAL_EXIT is received (CTRL-C
+ * on the command line will cause such an event to happen). If this event
+ * occurs it tells you what kind of exit signal was received, and asks
+ * the main loop to quit when it is finished by calling
+ * ecore_main_loop_quit().
+ *
+ * The handles returned by ecore_timer_add() and
+ * ecore_event_handler_add() are
+ * only stored here as an example. If you don't need to address the timer or
+ * event handler again you don't need to store the result, so just call the
+ * function, and don't assign the result to any variable.
+ *
+ * This program looks slightly more complex than needed to do these simple
+ * things, but in principle, programs don't get any more complex. You add more
+ * event handlers, for more events, will have more timers and such, BUT it all
+ * follows the same principles as shown in this example.
+ *
+ */
+
+/*
+ @page Ecore_Config_Page The Enlightened Property Library
+
+ The Enlightened Property Library (Ecore_Config) is an abstraction
+ from the complexities of writing your own configuration. It provides
+ many features using the Enlightenment 17 development libraries.
+
+ To use the library, you:
+ @li Set the default values of your properties.
+ @li Load the configuration from a file. You must set the default values
+ first, so that the library knows the correct type of each argument.
+
+ The following examples show how to use the Enlightened Property Library:
+ @li @link config_basic_example.c config_basic_example.c @endlink
+ @li @link config_listener_example.c config_listener_example.c @endlink
+
+ */
+
+/**
+ @page X_Window_System_Page X Window System
+
+ The Ecore library includes a wrapper for handling the X window system.
+ This page briefly explains what the X window system is and various terms
+ that are used.
+ */
+
+#ifndef _ECORE_H
+#define _ECORE_H
+
+#ifdef _MSC_VER
+# include <Evil.h>
+#endif
+
+#include <Eina.h>
+
+/* This include has been added to support Eo in Ecore */
+#include <Eo.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+#ifdef _WIN32
+# include <winsock2.h>
+#elif defined (__FreeBSD__) || defined (__OpenBSD__)
+# include <sys/select.h>
+# include <signal.h>
+#elif defined (__ANDROID__)
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+# if !defined (EXOTIC_NO_SIGNAL)
+# include <signal.h>
+# endif
+#endif
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_Init_Group Ecore initialization, shutdown functions and reset on fork.
+ *
+ * @{
+ */
+
+EAPI int ecore_init(void);
+EAPI int ecore_shutdown(void);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Main_Loop_Group Ecore main loop
+ *
+ * This group discusses functions that are acting on Ecore's main loop itself or
+ * on events and infrastructure directly linked to it. Most programs only need
+ * to start and end the main loop, the rest of the function discussed here are
+ * meant to be used in special situations, and with great care.
+ *
+ * For details on the usage of ecore's main loop and how it interacts with other
+ * ecore facilities see: @ref Ecore_Main_Loop_Page.
+ *
+ * @{
+ */
+
+#define ECORE_VERSION_MAJOR 1
+#define ECORE_VERSION_MINOR 8
+
+typedef struct _Ecore_Version
+{
+ int major;
+ int minor;
+ int micro;
+ int revision;
+} Ecore_Version;
+
+EAPI extern Ecore_Version *ecore_version;
+
+#define ECORE_CALLBACK_CANCEL EINA_FALSE /**< Return value to remove a callback */
+#define ECORE_CALLBACK_RENEW EINA_TRUE /**< Return value to keep a callback */
+
+#define ECORE_CALLBACK_PASS_ON EINA_TRUE /**< Return value to pass event to next handler */
+#define ECORE_CALLBACK_DONE EINA_FALSE /**< Return value to stop event handling */
+
+/**
+ * @typedef Ecore_Task_Cb Ecore_Task_Cb
+ * A callback run for a task (timer, idler, poller, animator, etc)
+ */
+typedef Eina_Bool (*Ecore_Task_Cb)(void *data);
+
+/**
+ * @typedef Ecore_Select_Function
+ * A function which can be used to replace select() in the main loop
+ */
+typedef int (*Ecore_Select_Function)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
+
+EAPI void ecore_main_loop_iterate(void);
+
+EAPI void ecore_main_loop_select_func_set(Ecore_Select_Function func);
+EAPI Ecore_Select_Function ecore_main_loop_select_func_get(void);
+
+EAPI Eina_Bool ecore_main_loop_glib_integrate(void);
+EAPI void ecore_main_loop_glib_always_integrate_disable(void);
+
+EAPI void ecore_main_loop_begin(void);
+EAPI void ecore_main_loop_quit(void);
+
+/**
+ * @typedef Ecore_Cb Ecore_Cb
+ * A generic callback called as a hook when a certain point in
+ * execution is reached.
+ */
+typedef void (*Ecore_Cb)(void *data);
+
+/**
+ * @typedef Ecore_Data_Cb Ecore_Data_Cb
+ * A callback which is used to return data to the main function
+ */
+typedef void *(*Ecore_Data_Cb)(void *data);
+
+/**
+ * Add a function to be called by ecore_fork_reset()
+ *
+ * This queues @p func to be called (and passed @p data as its argument) when
+ * ecore_fork_reset() is called. This allows other libraries and subsystems
+ * to also reset their internal state after a fork.
+ *
+ * @since 1.7
+ */
+EAPI Eina_Bool ecore_fork_reset_callback_add(Ecore_Cb func, const void *data);
+
+/**
+ * This removes the callback specified
+ *
+ * This deletes the callback added by ecore_fork_reset_callback_add() using
+ * the function and data pointer to specify which to remove.
+ *
+ * @since 1.7
+ */
+EAPI Eina_Bool ecore_fork_reset_callback_del(Ecore_Cb func, const void *data);
+
+/**
+ * Reset the ecore internal state after a fork
+ *
+ * Ecore maintains internal data that can be affected by the fork() system call
+ * which creates a duplicate of the current process. This also duplicates
+ * file descriptors which is problematic in that these file descriptors still
+ * point to their original sources. This function makes ecore reset internal
+ * state (e.g. pipes used for signalling between threads) so they function
+ * correctly afterwards.
+ *
+ * It is highly suggested that you call this function after any fork()
+ * system call inside the child process if you intend to use ecore features
+ * after this point and not call any exec() family functions. Not doing so
+ * will cause possible misbehaviour.
+ *
+ * @since 1.7
+ */
+EAPI void ecore_fork_reset(void);
+
+/**
+ * @brief Call callback asynchronously in the main loop.
+ * @since 1.1.0
+ *
+ * @param callback The callback to call in the main loop
+ * @param data The data to give to that call back
+ *
+ * For all calls that need to happen in the main loop (most EFL functions do),
+ * this helper function provides the infrastructure needed to do it safely
+ * by avoiding dead lock, race condition and properly wake up the main loop.
+ *
+ * Remember after that function call, you should never touch again the @p data
+ * in the thread, it is owned by the main loop and your callback should take
+ * care of freeing it if necessary.
+ */
+EAPI void ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data);
+
+/**
+ * @brief Call callback synchronously in the main loop.
+ * @since 1.1.0
+ *
+ * @param callback The callback to call in the main loop
+ * @param data The data to give to that call back
+ * @return the value returned by the callback in the main loop
+ *
+ * For all calls that need to happen in the main loop (most EFL functions do),
+ * this helper function provides the infrastructure needed to do it safely
+ * by avoiding dead lock, race condition and properly wake up the main loop.
+ *
+ * Remember this function will block until the callback is executed in the
+ * main loop. It can take time and you have no guaranty about the timeline.
+ */
+EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data);
+
+/**
+ * @brief This function suspend the main loop in a know state
+ * @since 1.1.0
+ *
+ * @result the number of time ecore_thread_main_loop_begin() has been called
+ * in this thread, if the main loop was suspended correctly. If not, it return @c -1.
+ *
+ * This function suspend the main loop in a know state, this let you
+ * use any EFL call you want after it return. Be carefully, the main loop
+ * is blocked until you call ecore_thread_main_loop_end(). This is
+ * the only sane way to achieve pseudo thread safety.
+ *
+ * Notice that until the main loop is blocked, the thread is blocked
+ * and their is noway around that.
+ *
+ * We still advise you, when possible, to use ecore_main_loop_thread_safe_call_async()
+ * as it will not block the thread nor the main loop.
+ */
+EAPI int ecore_thread_main_loop_begin(void);
+
+/**
+ * @brief Unlock the main loop.
+ * @since 1.1.0
+ *
+ * @result the number of time ecore_thread_main_loop_end() need to be called before
+ * the main loop is unlocked again. @c -1 will be returned if you are trying to unlock
+ * when there wasn't enough call to ecore_thread_main_loop_begin().
+ *
+ * After a call to ecore_thread_main_loop_begin(), you need to absolutely
+ * call ecore_thread_main_loop_end(), or you application will stay frozen.
+ */
+EAPI int ecore_thread_main_loop_end(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Event_Group Ecore Event functions
+ *
+ * Ecore events provide two main features that are of use to those using ecore:
+ * creating events and being notified of events. Those two will usually be used
+ * in different contexts, creating events is mainly done by libraries wrapping
+ * some system functionality while being notified of events is mainly a
+ * necessity of applications.
+ *
+ * For a program to be notified of events it's interested in it needs to have a
+ * function to process the event and to register that function as the callback
+ * to the event, that's all:
+ * @code
+ * ecore_event_handler_add(EVENT_TYPE, _my_event_handler, some_data);
+ * ...
+ * static Eina_Bool
+ * _my_event_handler(void *data, int type, void *event)
+ * {
+ * //data is some_data
+ * //event is provided by whoever created the event
+ * //Do really cool stuff with event
+ * }
+ * @endcode
+ *
+ * One very important thing to note here is the @c EVENT_TYPE, to register a
+ * handler for an event you must know its type before hand. Ecore provides
+ * the following events which are emitted in response to POSIX
+ * signals(https://en.wikipedia.org/wiki/Signal_%28computing%29):
+ * @li @b ECORE_EVENT_SIGNAL_USER
+ * @li @b ECORE_EVENT_SIGNAL_HUP
+ * @li @b ECORE_EVENT_SIGNAL_POWER
+ * @li @b ECORE_EVENT_SIGNAL_EXIT
+ *
+ * @warning Don't override these using the @c signal or @c sigaction calls.
+ * These, however, aren't the only signals one can handle. Many
+ * libraries(including ecore modules) have their own signals that can be
+ * listened for and handled, to do that one only needs to know the type of the
+ * event. This information can be found on the documentation of the library
+ * emitting the signal, so, for example, for events related to windowing one
+ * would look in @ref Ecore_Evas_Group.
+ *
+ * Examples of libraries that integrate into ecore's main loop by providing
+ * events are @ref Ecore_Con_Group, @ref Ecore_Evas_Group and @ref
+ * Ecore_Exe_Group, amongst others. This usage can be divided into two parts,
+ * setup and adding events. The setup is very simple, all that needs doing is
+ * getting a type id for the event:
+ * @code
+ * int MY_EV_TYPE = ecore_event_type_new();
+ * @endcode
+ * @note This variable should be declared in the header since it'll be needed by
+ * anyone wishing to register a handler to your event.
+ *
+ * The complexity of adding of an event to the queue depends on whether that
+ * event sends uses @c event, if it doesn't it a one-liner:
+ * @code
+ * ecore_event_add(MY_EV_TYPE, NULL, NULL, NULL);
+ * @endcode
+ * The usage when an @c event is needed is not that much more complex and can be
+ * seen in @ref ecore_event_add.
+ *
+ * Examples that deals with events:
+ * @li @ref ecore_event_example_01_c
+ * @li @ref ecore_event_example_02_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+#define ECORE_EVENT_NONE 0
+#define ECORE_EVENT_SIGNAL_USER 1 /**< User signal event */
+#define ECORE_EVENT_SIGNAL_HUP 2 /**< Hup signal event */
+#define ECORE_EVENT_SIGNAL_EXIT 3 /**< Exit signal event */
+#define ECORE_EVENT_SIGNAL_POWER 4 /**< Power signal event */
+#define ECORE_EVENT_SIGNAL_REALTIME 5 /**< Realtime signal event */
+#define ECORE_EVENT_COUNT 6
+
+typedef struct _Ecore_Win32_Handler Ecore_Win32_Handler; /**< A handle for HANDLE handlers on Windows */
+typedef struct _Ecore_Event_Handler Ecore_Event_Handler; /**< A handle for an event handler */
+typedef struct _Ecore_Event_Filter Ecore_Event_Filter; /**< A handle for an event filter */
+typedef struct _Ecore_Event Ecore_Event; /**< A handle for an event */
+typedef struct _Ecore_Event_Signal_User Ecore_Event_Signal_User; /**< User signal event */
+typedef struct _Ecore_Event_Signal_Hup Ecore_Event_Signal_Hup; /**< Hup signal event */
+typedef struct _Ecore_Event_Signal_Exit Ecore_Event_Signal_Exit; /**< Exit signal event */
+typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */
+typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */
+
+/**
+ * @typedef Ecore_Filter_Cb
+ * A callback used for filtering events from the main loop.
+ */
+typedef Eina_Bool (*Ecore_Filter_Cb)(void *data, void *loop_data, int type, void *event);
+
+/**
+ * @typedef Ecore_End_Cb Ecore_End_Cb
+ * This is the callback which is called at the end of a function,
+ * usually for cleanup purposes.
+ */
+typedef void (*Ecore_End_Cb)(void *user_data, void *func_data);
+
+/**
+ * @typedef Ecore_Event_Handler_Cb Ecore_Event_Handler_Cb
+ * A callback used by the main loop to handle events of a specified
+ * type.
+ */
+typedef Eina_Bool (*Ecore_Event_Handler_Cb)(void *data, int type, void *event);
+
+struct _Ecore_Event_Signal_User /** User signal event */
+{
+ int number; /**< The signal number. Either 1 or 2 */
+ void *ext_data; /**< Extension data - not used */
+
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+struct _Ecore_Event_Signal_Hup /** Hup signal event */
+{
+ void *ext_data; /**< Extension data - not used */
+
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+struct _Ecore_Event_Signal_Exit /** Exit request event */
+{
+ Eina_Bool interrupt : 1; /**< Set if the exit request was an interrupt signal*/
+ Eina_Bool quit : 1; /**< set if the exit request was a quit signal */
+ Eina_Bool terminate : 1; /**< Set if the exit request was a terminate signal */
+ void *ext_data; /**< Extension data - not used */
+
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+struct _Ecore_Event_Signal_Power /** Power event */
+{
+ void *ext_data; /**< Extension data - not used */
+
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+struct _Ecore_Event_Signal_Realtime /** Realtime event */
+{
+ int num; /**< The realtime signal's number */
+
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+/**
+ * @brief Add an event handler.
+ * @param type The type of the event this handler will get called for
+ * @param func The function to call when the event is found in the queue
+ * @param data A data pointer to pass to the called function @p func
+ * @return A new Event handler, or @c NULL on failure.
+ *
+ * Add an event handler to the list of handlers. This will, on success, return
+ * a handle to the event handler object that was created, that can be used
+ * later to remove the handler using ecore_event_handler_del(). The @p type
+ * parameter is the integer of the event type that will trigger this callback
+ * to be called. The callback @p func is called when this event is processed
+ * and will be passed the event type, a pointer to the private event
+ * structure that is specific to that event type, and a data pointer that is
+ * provided in this call as the @p data parameter.
+ *
+ * When the callback @p func is called, it must return 1 or 0. If it returns
+ * 1 (or ECORE_CALLBACK_PASS_ON), It will keep being called as per normal, for
+ * each handler set up for that event type. If it returns 0 (or
+ * ECORE_CALLBACK_DONE), it will cease processing handlers for that particular
+ * event, so all handler set to handle that event type that have not already
+ * been called, will not be.
+ */
+EAPI Ecore_Event_Handler *ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void *data);
+/**
+ * @brief Delete an event handler.
+ * @param event_handler Event handler handle to delete
+ * @return Data passed to handler
+ *
+ * Delete a specified event handler from the handler list. On success this will
+ * delete the event handler and return the pointer passed as @p data when the
+ * handler was added by ecore_event_handler_add(). On failure @c NULL will be
+ * returned. Once a handler is deleted it will no longer be called.
+ */
+EAPI void *ecore_event_handler_del(Ecore_Event_Handler *event_handler);
+/**
+ * @brief Add an event to the event queue.
+ * @param type The event type to add to the end of the event queue
+ * @param ev The data structure passed as @c event to event handlers
+ * @param func_free The function to be called to free @a ev
+ * @param data The data pointer to be passed to the free function
+ * @return A Handle for that event on success, otherwise NULL
+ *
+ * If it succeeds, an event of type @a type will be added to the queue for
+ * processing by event handlers added by ecore_event_handler_add(). The @a ev
+ * parameter will be passed as the @c event parameter of the handler. When the
+ * event is no longer needed, @a func_free will be called and passed @a ev for
+ * cleaning up. If @p func_free is NULL, free() will be called with the private
+ * structure pointer.
+ */
+EAPI Ecore_Event *ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data);
+/**
+ * @brief Delete an event from the queue.
+ * @param event The event handle to delete
+ * @return The data pointer originally set for the event free function
+ *
+ * This deletes the event @p event from the event queue, and returns the
+ * @p data parameter originally set when adding it with ecore_event_add(). This
+ * does not immediately call the free function, and it may be called later on
+ * cleanup, and so if the free function depends on the data pointer to work,
+ * you should defer cleaning of this till the free function is called later.
+ */
+EAPI void *ecore_event_del(Ecore_Event *event);
+/**
+ * @brief Get the data associated with an #Ecore_Event_Handler
+ * @param eh The event handler
+ * @return The data
+ *
+ * This function returns the data previously associated with @p eh by
+ * ecore_event_handler_add().
+ */
+EAPI void *ecore_event_handler_data_get(Ecore_Event_Handler *eh);
+/**
+ * @brief Set the data associated with an #Ecore_Event_Handler
+ * @param eh The event handler
+ * @param data The data to associate
+ * @return The previous data
+ *
+ * This function sets @p data to @p eh and returns the old data pointer
+ * which was previously associated with @p eh by ecore_event_handler_add().
+ */
+EAPI void *ecore_event_handler_data_set(Ecore_Event_Handler *eh, const void *data);
+/**
+ * @brief Allocate a new event type id sensibly and return the new id.
+ * @return A new event type id.
+ *
+ * This function allocates a new event type id and returns it. Once an event
+ * type has been allocated it can never be de-allocated during the life of
+ * the program. There is no guarantee of the contents of this event ID, or how
+ * it is calculated, except that the ID will be unique to the current instance
+ * of the process.
+ */
+EAPI int ecore_event_type_new(void);
+/**
+ * @brief Add a filter the current event queue.
+ *
+ * @param func_start Function to call just before filtering and return data
+ * @param func_filter Function to call on each event
+ * @param func_end Function to call after the queue has been filtered
+ * @param data Data to pass to the filter functions
+ * @return A filter handle on success, @c NULL otherwise.
+ *
+ * Adds a callback to filter events from the event queue. Filters are called on
+ * the queue just before Event handler processing to try and remove redundant
+ * events. Just as processing is about to start @a func_start is called and
+ * passed the @a data pointer, the return value of this functions is passed to
+ * @a func_filter as loop_data. @a func_filter is also passed @a data and the
+ * event type and event structure. If this @a func_filter returns
+ * @c EINA_FALSE, the event is removed from the queue, if it returns
+ * @c EINA_TRUE, the event is kept. When processing is finished @p func_end is
+ * called and is passed the loop_data(returned by @c func_start) and @p data
+ * pointer to clean up.
+ */
+EAPI Ecore_Event_Filter *ecore_event_filter_add(Ecore_Data_Cb func_start, Ecore_Filter_Cb func_filter, Ecore_End_Cb func_end, const void *data);
+/**
+ * @brief Delete an event filter.
+ * @param ef The event filter handle
+ * @return The data set for the filter on success, @c NULL otherwise.
+ *
+ * Delete a filter that has been added by its @p ef handle.
+ */
+EAPI void *ecore_event_filter_del(Ecore_Event_Filter *ef);
+/**
+ * @brief Return the current event type being handled.
+ * @return The current event type being handled if inside a handler callback,
+ * ECORE_EVENT_NONE otherwise
+ *
+ * If the program is currently inside an Ecore event handler callback this
+ * will return the type of the current event being processed.
+ *
+ * This is useful when certain Ecore modules such as Ecore_Evas "swallow"
+ * events and not all the original information is passed on. In special cases
+ * this extra information may be useful or needed and using this call can let
+ * the program know if the event type being handled is one it wants to get more
+ * information about.
+ */
+EAPI int ecore_event_current_type_get(void);
+/**
+ * @brief Return the current event type pointer handled.
+ * @return The current event pointer being handled if inside a handler callback,
+ * @c NULL otherwise.
+ *
+ * If the program is currently inside an Ecore event handler callback this
+ * will return the pointer of the current event being processed.
+ *
+ * This is useful when certain Ecore modules such as Ecore_Evas "swallow"
+ * events and not all the original information is passed on. In special cases
+ * this extra information may be useful or needed and using this call can let
+ * the program access the event data if the type of the event is handled by
+ * the program.
+ */
+EAPI void *ecore_event_current_event_get(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Exe_Group Process Spawning Functions
+ *
+ * This module is responsible for managing portable processes using Ecore.
+ * With this module you're able to spawn processes and you also can pause,
+ * quit your spawned processes.
+ * An interaction between your process and those spawned is possible
+ * using pipes or signals.
+ *
+ * Example
+ * @li @ref Ecore_exe_simple_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/** Inherit priority from parent process */
+#define ECORE_EXE_PRIORITY_INHERIT 9999
+
+EAPI extern int ECORE_EXE_EVENT_ADD; /**< A child process has been added */
+EAPI extern int ECORE_EXE_EVENT_DEL; /**< A child process has been deleted (it exited, naming consistent with the rest of ecore). */
+EAPI extern int ECORE_EXE_EVENT_DATA; /**< Data from a child process. */
+EAPI extern int ECORE_EXE_EVENT_ERROR; /**< Errors from a child process. */
+
+/**
+ * @enum _Ecore_Exe_Flags
+ * Flags for executing a child with its stdin and/or stdout piped back.
+ */
+enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or stdout piped back */
+{
+ ECORE_EXE_NONE = 0, /**< No exe flags at all */
+ ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */
+ ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */
+ ECORE_EXE_PIPE_ERROR = 4, /**< Exe Pipe error mask */
+ ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, /**< Reads are buffered until a newline and split 1 line per Ecore_Exe_Event_Data_Line */
+ ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered until a newline and split 1 line per Ecore_Exe_Event_Data_Line */
+ ECORE_EXE_PIPE_AUTO = 32, /**< stdout and stderr are buffered automatically */
+ ECORE_EXE_RESPAWN = 64, /**< FIXME: Exe is restarted if it dies */
+ ECORE_EXE_USE_SH = 128, /**< Use /bin/sh to run the command. */
+ ECORE_EXE_NOT_LEADER = 256, /**< Do not use setsid() to have the executed process be its own session leader */
+ ECORE_EXE_TERM_WITH_PARENT = 512 /**< Makes child receive SIGTERM when parent dies. */
+};
+typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags;
+
+/**
+ * @enum _Ecore_Exe_Win32_Priority
+ * Defines the priority of the proccess.
+ */
+enum _Ecore_Exe_Win32_Priority
+{
+ ECORE_EXE_WIN32_PRIORITY_IDLE, /**< Idle priority, for monitoring the system */
+ ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL, /**< Below default priority */
+ ECORE_EXE_WIN32_PRIORITY_NORMAL, /**< Default priority */
+ ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL, /**< Above default priority */
+ ECORE_EXE_WIN32_PRIORITY_HIGH, /**< High priority, use with care as other threads in the system will not get processor time */
+ ECORE_EXE_WIN32_PRIORITY_REALTIME /**< Realtime priority, should be almost never used as it can interrupt system threads that manage mouse input, keyboard input, and background disk flushing */
+};
+typedef enum _Ecore_Exe_Win32_Priority Ecore_Exe_Win32_Priority;
+
+typedef struct _Ecore_Exe Ecore_Exe; /**< A handle for spawned processes */
+
+/**
+ * @typedef Ecore_Exe_Cb Ecore_Exe_Cb
+ * A callback to run with the associated @ref Ecore_Exe, usually
+ * for cleanup purposes.
+ */
+typedef void (*Ecore_Exe_Cb)(void *data, const Ecore_Exe *exe);
+
+typedef struct _Ecore_Exe_Event_Add Ecore_Exe_Event_Add; /**< Spawned Exe add event */
+typedef struct _Ecore_Exe_Event_Del Ecore_Exe_Event_Del; /**< Spawned Exe exit event */
+typedef struct _Ecore_Exe_Event_Data_Line Ecore_Exe_Event_Data_Line; /**< Lines from a child process */
+typedef struct _Ecore_Exe_Event_Data Ecore_Exe_Event_Data; /**< Data from a child process */
+
+struct _Ecore_Exe_Event_Add /** Process add event */
+{
+ Ecore_Exe *exe; /**< The handle to the added process */
+ void *ext_data; /**< Extension data - not used */
+};
+
+struct _Ecore_Exe_Event_Del /** Process exit event */
+{
+ pid_t pid; /**< The process ID of the process that exited */
+ int exit_code; /**< The exit code of the process */
+ Ecore_Exe *exe; /**< The handle to the exited process, or @c NULL if not found */
+ int exit_signal; /** < The signal that caused the process to exit */
+ Eina_Bool exited : 1; /** < set to 1 if the process exited of its own accord */
+ Eina_Bool signalled : 1; /** < set to 1 id the process exited due to uncaught signal */
+ void *ext_data; /**< Extension data - not used */
+#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL)
+ siginfo_t data; /**< Signal info */
+#endif
+};
+
+struct _Ecore_Exe_Event_Data_Line /**< Lines from a child process */
+{
+ char *line; /**< The bytes of a line of buffered data */
+ int size; /**< The size of the line buffer in bytes */
+};
+
+struct _Ecore_Exe_Event_Data /** Data from a child process event */
+{
+ Ecore_Exe *exe; /**< The handle to the process */
+ void *data; /**< the raw binary data from the child process that was received */
+ int size; /**< the size of this data in bytes */
+ Ecore_Exe_Event_Data_Line *lines; /**< an array of line data if line buffered, the last one has it's line member set to @c NULL */
+};
+
+EAPI void ecore_exe_run_priority_set(int pri);
+EAPI int ecore_exe_run_priority_get(void);
+EAPI Ecore_Exe *ecore_exe_run(const char *exe_cmd, const void *data);
+EAPI Ecore_Exe *ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data);
+EAPI void ecore_exe_callback_pre_free_set(Ecore_Exe *exe, Ecore_Exe_Cb func);
+EAPI Eina_Bool ecore_exe_send(Ecore_Exe *exe, const void *data, int size);
+EAPI void ecore_exe_close_stdin(Ecore_Exe *exe);
+EAPI void ecore_exe_auto_limits_set(Ecore_Exe *exe, int start_bytes, int end_bytes, int start_lines, int end_lines);
+EAPI Ecore_Exe_Event_Data *ecore_exe_event_data_get(Ecore_Exe *exe, Ecore_Exe_Flags flags);
+EAPI void ecore_exe_event_data_free(Ecore_Exe_Event_Data *data);
+EAPI void *ecore_exe_free(Ecore_Exe *exe);
+EAPI pid_t ecore_exe_pid_get(const Ecore_Exe *exe);
+EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag);
+EAPI const char *ecore_exe_tag_get(const Ecore_Exe *exe);
+EAPI const char *ecore_exe_cmd_get(const Ecore_Exe *exe);
+EAPI void *ecore_exe_data_get(const Ecore_Exe *exe);
+EAPI void *ecore_exe_data_set(Ecore_Exe *exe, void *data);
+EAPI Ecore_Exe_Flags ecore_exe_flags_get(const Ecore_Exe *exe);
+EAPI void ecore_exe_pause(Ecore_Exe *exe);
+EAPI void ecore_exe_continue(Ecore_Exe *exe);
+EAPI void ecore_exe_interrupt(Ecore_Exe *exe);
+EAPI void ecore_exe_quit(Ecore_Exe *exe);
+EAPI void ecore_exe_terminate(Ecore_Exe *exe);
+EAPI void ecore_exe_kill(Ecore_Exe *exe);
+EAPI void ecore_exe_signal(Ecore_Exe *exe, int num);
+EAPI void ecore_exe_hup(Ecore_Exe *exe);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_FD_Handler_Group File Descriptor Handling Functions
+ *
+ * @brief Functions that deal with file descriptor handlers.
+ *
+ * File descriptor handlers facilitate reading, writing and checking for errors
+ * without blocking the program or doing expensive pooling. This can be used to
+ * monitor a socket, pipe, or other stream for which an FD can be had.
+ *
+ * @warning File descriptor handlers can't be used to monitor for file creation,
+ * modification or deletion, see @ref Ecore_File_Group for this.
+ *
+ * One common FD to be monitored is the standard input(stdin), monitoring it for
+ * reading requires a single call:
+ * @code
+ * static Eina_Bool
+ * _my_cb_func(void *data, Ecore_Fd_Handler *handler)
+ * {
+ * char c;
+ * scanf("%c", &c); //Guaranteed not to block
+ * ... do stuff with c ...
+ * }
+ * ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ, _my_cb_func, NULL, NULL, NULL);
+ * @endcode
+ *
+ * When using a socket, pipe or other stream it's important to remember that
+ * errors may occur and as such to monitor not only for reading/writing but also
+ * for errors using the @ref ECORE_FD_ERROR flag.
+ *
+ * Example of use of a file descriptor handler:
+ * @li @ref ecore_fd_handler_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+typedef struct _Ecore_Fd_Handler Ecore_Fd_Handler; /**< A handle for Fd handlers */
+
+/**
+ * @enum _Ecore_Fd_Handler_Flags
+ * What to monitor the file descriptor for: reading, writing or error.
+ */
+enum _Ecore_Fd_Handler_Flags
+{
+ ECORE_FD_READ = 1, /**< Fd Read mask */
+ ECORE_FD_WRITE = 2, /**< Fd Write mask */
+ ECORE_FD_ERROR = 4 /**< Fd Error mask */
+};
+typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags;
+
+/**
+ * @typedef Ecore_Fd_Cb Ecore_Fd_Cb
+ * A callback used by an @ref Ecore_Fd_Handler.
+ */
+typedef Eina_Bool (*Ecore_Fd_Cb)(void *data, Ecore_Fd_Handler *fd_handler);
+
+/**
+ * @typedef Ecore_Fd_Prep_Cb Ecore_Fd_Prep_Cb
+ * A callback used by an @ref Ecore_Fd_Handler.
+ */
+typedef void (*Ecore_Fd_Prep_Cb)(void *data, Ecore_Fd_Handler *fd_handler);
+
+/**
+ * @typedef Ecore_Win32_Handle_Cb Ecore_Win32_Handle_Cb
+ * A callback used by an @ref Ecore_Win32_Handler.
+ */
+typedef Eina_Bool (*Ecore_Win32_Handle_Cb)(void *data, Ecore_Win32_Handler *wh);
+
+/**
+ * @brief Adds a callback for activity on the given file descriptor.
+ *
+ * @param fd The file descriptor to watch.
+ * @param flags To monitor it for reading use @c ECORE_FD_READ, for writing @c
+ * ECORE_FD_WRITE, and for error @c ECORE_FD_ERROR. Values by |(ored).
+ * @param func The callback function.
+ * @param data The data to pass to the callback.
+ * @param buf_func The function to call to check if any data has been buffered
+ * and already read from the fd. May be @c NULL.
+ * @param buf_data The data to pass to the @p buf_func function.
+ * @return A fd handler handle on success, @c NULL otherwise.
+ *
+ * @a func will be called during the execution of @ref Ecore_Main_Loop_Page
+ * when the file descriptor is available for reading, writing, or there has been
+ * an error(depending on the given @a flags).
+ *
+ * When @a func returns ECORE_CALLBACK_CANCEL, it indicates that the
+ * handler should be marked for deletion (identical to calling @ref
+ * ecore_main_fd_handler_del).
+ *
+ * @warning @a buf_func is meant for @b internal use only and should be @b
+ * avoided.
+ *
+ * The return value of @a buf_func has a different meaning, when it returns
+ * ECORE_CALLBACK_CANCEL, it indicates that @a func @b shouldn't be called, and
+ * when it returns ECORE_CALLBACK_RENEW it indicates @a func should be called.
+ * The return value of @a buf_func will not cause the FD handler to be deleted.
+ *
+ * @a buf_func is called during event loop handling to check if data that has
+ * been read from the file descriptor is in a buffer and is available to read.
+ * Some systems, notably xlib, handle their own buffering, and would otherwise
+ * not work with select(). These systems should use a @a buf_func. This is a
+ * most annoying hack, only ecore_x uses it, so refer to that for an example.
+ *
+ * @warning This function should @b not be used for monitoring "normal" files, like text files.
+ *
+ */
+EAPI Ecore_Fd_Handler *ecore_main_fd_handler_add(int fd, Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb func, const void *data, Ecore_Fd_Cb buf_func, const void *buf_data);
+
+/**
+ * @brief Adds a callback for activity on the given file descriptor.
+ *
+ * @param fd The file descriptor to watch.
+ * @param flags To monitor it for reading use @c ECORE_FD_READ, for writing @c
+ * ECORE_FD_WRITE, and for error @c ECORE_FD_ERROR. Values by |(ored).
+ * @param func The callback function.
+ * @param data The data to pass to the callback.
+ * @param buf_func The function to call to check if any data has been buffered
+ * and already read from the fd. May be @c NULL.
+ * @param buf_data The data to pass to the @p buf_func function.
+ * @return A fd handler handle on success, @c NULL otherwise.
+ *
+ * This function is identical to ecore_main_fd_handler_add, except that it supports regular files.
+ * @warning This function should ONLY be called with ECORE_FD_ERROR, otherwise it will call the fd
+ * handler constantly.
+ * @warning Do not use this function unless you know what you are doing.
+ *
+ * @since 1.7
+ */
+EAPI Ecore_Fd_Handler *ecore_main_fd_handler_file_add(int fd, Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb func, const void *data, Ecore_Fd_Cb buf_func, const void *buf_data);
+
+/**
+ * @brief Set the prepare callback with data for a given #Ecore_Fd_Handler
+ *
+ * @param fd_handler The fd handler
+ * @param func The prep function
+ * @param data The data to pass to the prep function
+ *
+ * This function will be called prior to any fd handler's callback function
+ * (even the other fd handlers), before entering the main loop select function.
+ *
+ * @note Once a prepare callback is set for a fd handler, it cannot be changed.
+ * You need to delete the fd handler and create a new one, to set another
+ * callback.
+ * @note You probably don't need this function. It is only necessary for very
+ * uncommon cases that need special behavior.
+ */
+EAPI void ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Prep_Cb func, const void *data);
+/**
+ * @brief Marks an FD handler for deletion.
+ * @param fd_handler The FD handler.
+ * @return The data pointer set using @ref ecore_main_fd_handler_add, for
+ * @a fd_handler on success, @c NULL otherwise.
+ * This function marks an fd handler to be deleted during an iteration of the
+ * main loop. It does NOT close the associated fd!
+ *
+ * @warning If the underlying fd is already closed ecore may complain if the
+ * main loop is using epoll internally, and also in some rare cases this may
+ * cause crashes and instability. Remember to delete your fd handlers before the
+ * fds they listen to are closed.
+ */
+EAPI void *ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler);
+/**
+ * @brief Retrieves the file descriptor that the given handler is handling.
+ * @param fd_handler The given FD handler.
+ * @return The file descriptor the handler is watching.
+ */
+EAPI int ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler);
+/**
+ * @brief Gets which flags are active on an FD handler.
+ * @param fd_handler The given FD handler.
+ * @param flags The flags, @c ECORE_FD_READ, @c ECORE_FD_WRITE or
+ * @c ECORE_FD_ERROR to query.
+ * @return @c EINA_TRUE if any of the given flags are active, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags);
+/**
+ * @brief Set what active streams the given FD handler should be monitoring.
+ * @param fd_handler The given FD handler.
+ * @param flags The flags to be watching.
+ */
+EAPI void ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags);
+
+EAPI Ecore_Win32_Handler *ecore_main_win32_handler_add(void *h, Ecore_Win32_Handle_Cb func, const void *data);
+EAPI void *ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Poller_Group Ecore Poll functions
+ *
+ * Ecore poller provides infrastructure for the creation of pollers. Pollers
+ * are, in essence, callbacks that share a single timer per type. Because not
+ * all pollers need to be called at the same frequency the user may specify the
+ * frequency in ticks(each expiration of the shared timer is called a tick, in
+ * ecore poller parlance) for each added poller. Ecore pollers should only be
+ * used when the poller doesn't have specific requirements on the exact times
+ * to poll.
+ *
+ * This architecture means that the main loop is only woken up once to handle
+ * all pollers of that type, this will save power as the CPU has more of a
+ * chance to go into a low power state the longer it is asleep for, so this
+ * should be used in situations where power usage is a concern.
+ *
+ * For now only 1 core poller type is supported: ECORE_POLLER_CORE, the default
+ * interval for ECORE_POLLER_CORE is 0.125(or 1/8th) second.
+ *
+ * The creation of a poller is extremely simple and only requires one line:
+ * @code
+ * ecore_poller_add(ECORE_POLLER_CORE, 1, my_poller_function, NULL);
+ * @endcode
+ * This sample creates a poller to call @c my_poller_function at every tick with
+ * @c NULL as data.
+ *
+ * Example:
+ * @li @ref ecore_poller_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/**
+ * @enum _Ecore_Poller_Type
+ * Defines the frequency of ticks for the poller.
+ */
+enum _Ecore_Poller_Type /* Poller types */
+{
+ ECORE_POLLER_CORE = 0 /**< The core poller interval */
+};
+typedef enum _Ecore_Poller_Type Ecore_Poller_Type;
+
+/*
+ * @since 1.8
+ */
+
+typedef Eo Ecore_Poller; /**< A handle for pollers */
+
+#define ECORE_POLLER_CLASS ecore_poller_class_get()
+const Eo_Class *ecore_poller_class_get(void) EINA_CONST;
+extern EAPI Eo_Op ECORE_POLLER_BASE_ID;
+
+enum
+{
+ ECORE_POLLER_SUB_ID_CONSTRUCTOR,
+ ECORE_POLLER_SUB_ID_INTERVAL_SET,
+ ECORE_POLLER_SUB_ID_INTERVAL_GET,
+ ECORE_POLLER_SUB_ID_LAST,
+};
+
+#define ECORE_POLLER_ID(sub_id) (ECORE_POLLER_BASE_ID + sub_id)
+
+/**
+ * @def ecore_poller_constructor
+ * @since 1.8
+ *
+ * Contructor with parameters for Ecore Poller.
+ *
+ * @param[in] type
+ * @param[in] interval
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_poller_constructor(type, interval, func, data) ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(Ecore_Poller_Type, type), EO_TYPECHECK(int, interval), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def ecore_poller_interval_set
+ * @since 1.8
+ *
+ * Changes the polling interval rate of poller.
+ *
+ * @param[in] interval
+ * @param[out] ret
+ *
+ * @see ecore_poller_poller_interval_set
+ */
+#define ecore_poller_interval_set(interval, ret) ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_INTERVAL_SET), EO_TYPECHECK(int, interval), EO_TYPECHECK(Eina_Bool *, ret)
+
+/**
+ * @def ecore_poller_interval_get
+ * @since 1.8
+ *
+ * Gets the polling interval rate of poller.
+ *
+ * @param[out] ret
+ *
+ * @see ecore_poller_poller_interval_get
+ */
+#define ecore_poller_interval_get(ret) ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_INTERVAL_GET), EO_TYPECHECK(int *, ret)
+
+
+/**
+ * @brief Sets the time(in seconds) between ticks for the given poller type.
+ * @param type The poller type to adjust.
+ * @param poll_time The time(in seconds) between ticks of the timer.
+ *
+ * This will adjust the time between ticks of the given timer type defined by
+ * @p type to the time period defined by @p poll_time.
+ */
+EAPI void ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time);
+/**
+ * @brief Gets the time(in seconds) between ticks for the given poller type.
+ * @param type The poller type to query.
+ * @return The time in seconds between ticks of the poller timer.
+ *
+ * This will get the time between ticks of the specified poller timer.
+ */
+EAPI double ecore_poller_poll_interval_get(Ecore_Poller_Type type);
+/**
+ * @brief Changes the polling interval rate of @p poller.
+ * @param poller The Ecore_Poller to change the interval of.
+ * @param interval The tick interval to set; must be a power of 2 and <= 32768.
+ * @return Returns true on success, false on failure.
+ *
+ * This allows the changing of a poller's polling interval. It is useful when
+ * you want to alter a poll rate without deleting and re-creating a poller.
+ */
+EAPI Eina_Bool ecore_poller_poller_interval_set(Ecore_Poller *poller, int interval);
+/**
+ * @brief Gets the polling interval rate of @p poller.
+ * @param poller The Ecore_Poller to change the interval of.
+ * @return Returns the interval, in ticks, that @p poller polls at.
+ *
+ * This returns a poller's polling interval, or 0 on error.
+ */
+EAPI int ecore_poller_poller_interval_get(Ecore_Poller *poller);
+/**
+ * @brief Creates a poller to call the given function at a particular tick interval.
+ * @param type The ticker type to attach the poller to. Must be ECORE_POLLER_CORE.
+ * @param interval The poll interval.
+ * @param func The poller function.
+ * @param data Data to pass to @a func when it is called.
+ * @return A poller object on success, @c NULL otherwise.
+ *
+ * This function adds @a func as a poller callback that will be called every @a
+ * interval ticks together with other pollers of type @a type. @a func will be
+ * passed the @p data pointer as a parameter.
+ *
+ * The @p interval must be between 1 and 32768 inclusive, and must be a power of
+ * 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768). The exact tick in which @a func
+ * will be called is undefined, as only the interval between calls can be
+ * defined. Ecore will endeavor to keep pollers synchronized and to call as
+ * many in 1 wakeup event as possible. If @a interval is not a power of two, the
+ * closest power of 2 greater than @a interval will be used.
+ *
+ * When the poller @p func is called, it must return a value of either
+ * ECORE_CALLBACK_RENEW(or 1) or ECORE_CALLBACK_CANCEL(or 0). If it
+ * returns 1, it will be called again at the next tick, or if it returns
+ * 0 it will be deleted automatically making any references/handles for it
+ * invalid.
+ */
+EAPI Ecore_Poller *ecore_poller_add(Ecore_Poller_Type type, int interval, Ecore_Task_Cb func, const void *data);
+/**
+ * @brief Delete the specified poller from the timer list.
+ * @param poller The poller to delete.
+ * @return The data pointer set for the timer when @ref ecore_poller_add was
+ * called on success, @c NULL otherwise.
+ *
+ * @note @a poller must be a valid handle. If the poller function has already
+ * returned 0, the handle is no longer valid (and does not need to be deleted).
+ */
+EAPI void *ecore_poller_del(Ecore_Poller *poller);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Animator_Group Ecore Animator functions
+ *
+ * @brief Ecore animators are a helper to simplify creating
+ * animations.
+ *
+ * Creating an animation is as simple as saying for how long it
+ * should be run and having a callback that does the animation,
+ * something like this:
+ * @code
+ * static Eina_Bool
+ * _do_animation(void *data, double pos)
+ * {
+ * evas_object_move(data, 100 * pos, 100 * pos);
+ * ... do some more animating ...
+ * }
+ * ...
+ *ecore_animator_timeline_add(2, _do_animation, my_evas_object);
+ * @endcode
+ * In the sample above we create an animation to move
+ * @c my_evas_object from position (0,0) to (100,100) in 2 seconds.
+ *
+ * If your animation will run for an unspecified amount of time you
+ * can use ecore_animator_add(), which is like using
+ *ecore_timer_add() with the interval being the
+ * @ref ecore_animator_frametime_set "framerate". Note that this has
+ * tangible benefits to creating a timer for each animation in terms
+ * of performance.
+ *
+ * For a more detailed example that show several animation see
+ * @ref tutorial_ecore_animator.
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/*
+ * @since 1.8
+ */
+typedef Eo Ecore_Animator; /**< A handle for animators */
+#define ECORE_ANIMATOR_CLASS ecore_animator_class_get()
+const Eo_Class *ecore_animator_class_get(void) EINA_CONST;
+
+extern EAPI Eo_Op ECORE_ANIMATOR_BASE_ID;
+
+enum
+{
+ ECORE_ANIMATOR_SUB_ID_CONSTRUCTOR,
+ ECORE_ANIMATOR_SUB_ID_TIMELINE_CONSTRUCTOR,
+ ECORE_ANIMATOR_SUB_ID_LAST
+};
+
+#define ECORE_ANIMATOR_ID(sub_id) (ECORE_ANIMATOR_BASE_ID + sub_id)
+
+/**
+ * @def ecore_animator_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_animator_constructor(func, data) ECORE_ANIMATOR_ID(ECORE_ANIMATOR_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def ecore_animator_timeline_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] runtime
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_animator_timeline_constructor(runtime, func, data) ECORE_ANIMATOR_ID(ECORE_ANIMATOR_SUB_ID_TIMELINE_CONSTRUCTOR), EO_TYPECHECK(double, runtime), EO_TYPECHECK(Ecore_Timeline_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @enum _Ecore_Pos_Map
+ * Defines the position mappings for the animation.
+ */
+enum _Ecore_Pos_Map /* Position mappings */
+{
+ ECORE_POS_MAP_LINEAR, /**< Linear 0.0 -> 1.0 */
+ ECORE_POS_MAP_ACCELERATE, /**< Start slow then speed up */
+ ECORE_POS_MAP_DECELERATE, /**< Start fast then slow down */
+ ECORE_POS_MAP_SINUSOIDAL, /**< Start slow, speed up then slow down at end */
+ ECORE_POS_MAP_ACCELERATE_FACTOR, /**< Start slow then speed up, v1 being a power factor, 0.0 being linear, 1.0 being normal accelerate, 2.0 being much more pronounced accelerate (squared), 3.0 being cubed, etc. */
+ ECORE_POS_MAP_DECELERATE_FACTOR, /**< Start fast then slow down, v1 being a power factor, 0.0 being linear, 1.0 being normal decelerate, 2.0 being much more pronounced decelerate (squared), 3.0 being cubed, etc. */
+ ECORE_POS_MAP_SINUSOIDAL_FACTOR, /**< Start slow, speed up then slow down at end, v1 being a power factor, 0.0 being linear, 1.0 being normal sinusoidal, 2.0 being much more pronounced sinusoidal (squared), 3.0 being cubed, etc. */
+ ECORE_POS_MAP_DIVISOR_INTERP, /**< Start at gradient * v1, interpolated via power of v2 curve */
+ ECORE_POS_MAP_BOUNCE, /**< Start at 0.0 then "drop" like a ball bouncing to the ground at 1.0, and bounce v2 times, with decay factor of v1 */
+ ECORE_POS_MAP_SPRING /**< Start at 0.0 then "wobble" like a spring rest position 1.0, and wobble v2 times, with decay factor of v1 */
+};
+typedef enum _Ecore_Pos_Map Ecore_Pos_Map;
+
+/**
+ * @enum _Ecore_Animator_Source
+ * Defines the timing sources for animators.
+ */
+enum _Ecore_Animator_Source /* Timing sources for animators */
+{
+ ECORE_ANIMATOR_SOURCE_TIMER, /**< The default system clock/timer based animator that ticks every "frametime" seconds */
+ ECORE_ANIMATOR_SOURCE_CUSTOM /**< A custom animator trigger that you need to call ecore_animator_trigger() to make it tick */
+};
+typedef enum _Ecore_Animator_Source Ecore_Animator_Source;
+
+/**
+ * @typedef Ecore_Timeline_Cb Ecore_Timeline_Cb
+ * A callback run for a task (animators with runtimes)
+ */
+typedef Eina_Bool (*Ecore_Timeline_Cb)(void *data, double pos);
+
+/**
+ * @brief Add an animator to call @p func at every animation tick during main
+ * loop execution.
+ *
+ * @param func The function to call when it ticks off
+ * @param data The data to pass to the function
+ * @return A handle to the new animator
+ *
+ * This function adds a animator and returns its handle on success and @c NULL
+ * on failure. The function @p func will be called every N seconds where N is
+ * the @p frametime interval set by ecore_animator_frametime_set(). The
+ * function will be passed the @p data pointer as its parameter.
+ *
+ * When the animator @p func is called, it must return a value of either 1 or
+ * 0. If it returns 1 (or ECORE_CALLBACK_RENEW), it will be called again at
+ * the next tick, or if it returns 0 (or ECORE_CALLBACK_CANCEL) it will be
+ * deleted automatically making any references/handles for it invalid.
+ *
+ * @note The default @p frametime value is 1/30th of a second.
+ *
+ * @see ecore_animator_timeline_add()
+ * @see ecore_animator_frametime_set()
+ */
+EAPI Ecore_Animator *ecore_animator_add(Ecore_Task_Cb func, const void *data);
+/**
+ * @brief Add a animator that runs for a limited time
+ *
+ * @param runtime The time to run in seconds
+ * @param func The function to call when it ticks off
+ * @param data The data to pass to the function
+ * @return A handle to the new animator
+ *
+ * This function is just like ecore_animator_add() except the animator only
+ * runs for a limited time specified in seconds by @p runtime. Once the
+ * runtime the animator has elapsed (animator finished) it will automatically
+ * be deleted. The callback function @p func can return ECORE_CALLBACK_RENEW
+ * to keep the animator running or ECORE_CALLBACK_CANCEL ro stop it and have
+ * it be deleted automatically at any time.
+ *
+ * The @p func will ALSO be passed a position parameter that will be in value
+ * from 0.0 to 1.0 to indicate where along the timeline (0.0 start, 1.0 end)
+ * the animator run is at. If the callback wishes not to have a linear
+ * transition it can "map" this value to one of several curves and mappings
+ * via ecore_animator_pos_map().
+ *
+ * @note The default @p frametime value is 1/30th of a second.
+ *
+ * @see ecore_animator_add()
+ * @see ecore_animator_pos_map()
+ * @since 1.1.0
+ */
+EAPI Ecore_Animator *ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data);
+/**
+ * @brief Delete the specified animator from the animator list.
+ *
+ * @param animator The animator to delete
+ * @return The data pointer set for the animator on add
+ *
+ * Delete the specified @p animator from the set of animators that are
+ * executed during main loop execution. This function returns the data
+ * parameter that was being passed to the callback on success, or @c NULL on
+ * failure. After this call returns the specified animator object @p animator
+ * is invalid and should not be used again. It will not get called again after
+ * deletion.
+ */
+EAPI void *ecore_animator_del(Ecore_Animator *animator);
+/**
+ * @brief Suspend the specified animator.
+ *
+ * @param animator The animator to delete
+ *
+ * The specified @p animator will be temporarily removed from the set of
+ * animators that are executed during main loop.
+ *
+ * @warning Freezing an animator doesn't freeze accounting of how long that
+ * animator has been running. Therefore if the animator was created with
+ *ecore_animator_timeline_add() the @p pos argument given to the callback
+ * will increase as if the animator hadn't been frozen and the animator may
+ * have it's execution halted if @p runtime elapsed.
+ */
+EAPI void ecore_animator_freeze(Ecore_Animator *animator);
+/**
+ * @brief Restore execution of the specified animator.
+ *
+ * @param animator The animator to delete
+ *
+ * The specified @p animator will be put back in the set of animators that are
+ * executed during main loop.
+ */
+EAPI void ecore_animator_thaw(Ecore_Animator *animator);
+/**
+ * @brief Set the animator call interval in seconds.
+ *
+ * @param frametime The time in seconds in between animator ticks.
+ *
+ * This function sets the time interval (in seconds) between animator ticks.
+ * At every tick the callback of every existing animator will be called.
+ *
+ * @warning Too small a value may cause performance issues and too high a
+ * value may cause your animation to seem "jerky".
+ *
+ * @note The default @p frametime value is 1/30th of a second.
+ */
+EAPI void ecore_animator_frametime_set(double frametime);
+/**
+ * @brief Get the animator call interval in seconds.
+ *
+ * @return The time in second in between animator ticks.
+ *
+ * This function retrieves the time in seconds between animator ticks.
+ *
+ * @see ecore_animator_frametime_set()
+ */
+EAPI double ecore_animator_frametime_get(void);
+/**
+ * @brief Maps an input position from 0.0 to 1.0 along a timeline to a
+ * position in a different curve.
+ *
+ * @param pos The input position to map
+ * @param map The mapping to use
+ * @param v1 A parameter use by the mapping (pass 0.0 if not used)
+ * @param v2 A parameter use by the mapping (pass 0.0 if not used)
+ * @return The mapped value
+ *
+ * Takes an input position (0.0 to 1.0) and maps to a new position (normally
+ * between 0.0 and 1.0, but it may go above/below 0.0 or 1.0 to show that it
+ * has "overshot" the mark) using some interpolation (mapping) algorithm.
+ *
+ * This function useful to create non-linear animations. It offers a variety
+ * of possible animation curves to be used:
+ * @li ECORE_POS_MAP_LINEAR - Linear, returns @p pos
+ * @li ECORE_POS_MAP_ACCELERATE - Start slow then speed up
+ * @li ECORE_POS_MAP_DECELERATE - Start fast then slow down
+ * @li ECORE_POS_MAP_SINUSOIDAL - Start slow, speed up then slow down at end
+ * @li ECORE_POS_MAP_ACCELERATE_FACTOR - Start slow then speed up, v1 being a
+ * power factor, 0.0 being linear, 1.0 being ECORE_POS_MAP_ACCELERATE, 2.0
+ * being much more pronounced accelerate (squared), 3.0 being cubed, etc.
+ * @li ECORE_POS_MAP_DECELERATE_FACTOR - Start fast then slow down, v1 being a
+ * power factor, 0.0 being linear, 1.0 being ECORE_POS_MAP_DECELERATE, 2.0
+ * being much more pronounced decelerate (squared), 3.0 being cubed, etc.
+ * @li ECORE_POS_MAP_SINUSOIDAL_FACTOR - Start slow, speed up then slow down
+ * at end, v1 being a power factor, 0.0 being linear, 1.0 being
+ * ECORE_POS_MAP_SINUSOIDAL, 2.0 being much more pronounced sinusoidal
+ * (squared), 3.0 being cubed, etc.
+ * @li ECORE_POS_MAP_DIVISOR_INTERP - Start at gradient * v1, interpolated via
+ * power of v2 curve
+ * @li ECORE_POS_MAP_BOUNCE - Start at 0.0 then "drop" like a ball bouncing to
+ * the ground at 1.0, and bounce v2 times, with decay factor of v1
+ * @li ECORE_POS_MAP_SPRING - Start at 0.0 then "wobble" like a spring rest
+ * position 1.0, and wobble v2 times, with decay factor of v1
+ * @note When not listed v1 and v2 have no effect.
+ *
+ * @image html ecore-pos-map.png
+ * @image latex ecore-pos-map.eps width=\textwidth
+ *
+ * One way to use this would be:
+ * @code
+ * double pos; // input position in a timeline from 0.0 to 1.0
+ * double out; // output position after mapping
+ * int x1, y1, x2, y2; // x1 & y1 are start position, x2 & y2 are end position
+ * int x, y; // x & y are the calculated position
+ *
+ * out = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
+ * x = (x1 * out) + (x2 * (1.0 - out));
+ * y = (y1 * out) + (y2 * (1.0 - out));
+ * move_my_object_to(myobject, x, y);
+ * @endcode
+ * This will make an animation that bounces 7 each times diminishing by a
+ * factor of 1.8.
+ *
+ * @see _Ecore_Pos_Map
+ *
+ * @since 1.1.0
+ */
+EAPI double ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2);
+/**
+ * @brief Set the source of animator ticks for the mainloop
+ *
+ * @param source The source of animator ticks to use
+ *
+ * This sets the source of animator ticks. When an animator is active the
+ * mainloop will "tick" over frame by frame calling all animators that are
+ * registered until none are. The mainloop will tick at a given rate based
+ * on the animator source. The default source is the system clock timer
+ * source - ECORE_ANIMATOR_SOURCE_TIMER. This source uses the system clock
+ * to tick over every N seconds (specified by ecore_animator_frametime_set(),
+ * with the default being 1/30th of a second unless set otherwise). You can
+ * set a custom tick source by setting the source to
+ * ECORE_ANIMATOR_SOURCE_CUSTOM and then drive it yourself based on some input
+ * tick source (like another application via ipc, some vertical blanking
+ * interrupt interrupt etc.) using
+ *ecore_animator_custom_source_tick_begin_callback_set() and
+ *ecore_animator_custom_source_tick_end_callback_set() to set the functions
+ * that will be called to start and stop the ticking source, which when it
+ * gets a "tick" should call ecore_animator_custom_tick() to make the "tick" over 1
+ * frame.
+ */
+EAPI void ecore_animator_source_set(Ecore_Animator_Source source);
+/**
+ * @brief Get the animator source currently set.
+ *
+ * @return The current animator source
+ *
+ * This gets the current animator source.
+ *
+ * @see ecore_animator_source_set()
+ */
+EAPI Ecore_Animator_Source ecore_animator_source_get(void);
+/**
+ * @brief Set the function that begins a custom animator tick source
+ *
+ * @param func The function to call when ticking is to begin
+ * @param data The data passed to the tick begin function as its parameter
+ *
+ * The Ecore Animator infrastructure handles tracking if animators are needed
+ * or not and which ones need to be called and when, but when the tick source
+ * is custom, you have to provide a tick source by calling
+ *ecore_animator_custom_tick() to indicate a frame tick happened. In order
+ * to allow the source of ticks to be dynamically enabled or disabled as
+ * needed, the @p func when set is called to enable the tick source to
+ * produce tick events that call ecore_animator_custom_tick(). If @p func
+ * is @c NULL then no function is called to begin custom ticking.
+ *
+ * @see ecore_animator_source_set()
+ * @see ecore_animator_custom_source_tick_end_callback_set()
+ * @see ecore_animator_custom_tick()
+ */
+EAPI void ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data);
+/**
+ * @brief Set the function that ends a custom animator tick source
+ *
+ * @param func The function to call when ticking is to end
+ * @param data The data passed to the tick end function as its parameter
+ *
+ * This function is a matching pair to the function set by
+ * ecore_animator_custom_source_tick_begin_callback_set() and is called
+ * when ticking is to stop. If @p func is @c NULL then no function will be
+ * called to stop ticking. For more information please see
+ * ecore_animator_custom_source_tick_begin_callback_set().
+ *
+ * @see ecore_animator_source_set()
+ * @see ecore_animator_custom_source_tick_begin_callback_set()
+ * @see ecore_animator_custom_tick()
+ */
+EAPI void ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data);
+/**
+ * @brief Trigger a custom animator tick
+ *
+ * When animator source is set to ECORE_ANIMATOR_SOURCE_CUSTOM, then calling
+ * this function triggers a run of all animators currently registered with
+ * Ecore as this indicates a "frame tick" happened. This will do nothing if
+ * the animator source(set by ecore_animator_source_set()) is not set to
+ * ECORE_ANIMATOR_SOURCE_CUSTOM.
+ *
+ * @see ecore_animator_source_set()
+ * @see ecore_animator_custom_source_tick_begin_callback_set
+ * @see ecore_animator_custom_source_tick_end_callback_set()()
+ */
+EAPI void ecore_animator_custom_tick(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Time_Group Ecore time functions
+ *
+ * These are function to retrieve time in a given format.
+ *
+ * Examples:
+ * @li @ref ecore_time_functions_example_c
+ * @{
+ */
+EAPI double ecore_time_get(void);
+EAPI double ecore_time_unix_get(void);
+EAPI double ecore_loop_time_get(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Timer_Group Ecore Timer functions
+ *
+ * Ecore provides very flexible timer functionality. The basic usage of timers,
+ * to call a certain function at a certain interval can be achieved with a
+ * single line:
+ * @code
+ * Eina_Bool my_func(void *data) {
+ * do_funky_stuff_with_data(data);
+ * return EINA_TRUE;
+ * }
+ * ecore_timer_add(interval_in_seconds, my_func, data_given_to_function);
+ * @endcode
+ * @note If the function was to be executed only once simply return
+ * @c EINA_FALSE instead.
+ *
+ * An example that shows the usage of a lot of these:
+ * @li @ref ecore_timer_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/*
+ * @since 1.8
+ */
+typedef Eo Ecore_Timer; /**< A handle for timers */
+
+#define ECORE_TIMER_CLASS ecore_timer_class_get()
+const Eo_Class *ecore_timer_class_get(void) EINA_CONST;
+extern EAPI Eo_Op ECORE_TIMER_BASE_ID;
+
+enum
+{
+ ECORE_TIMER_SUB_ID_CONSTRUCTOR,
+ ECORE_TIMER_SUB_ID_LOOP_CONSTRUCTOR,
+ ECORE_TIMER_SUB_ID_INTERVAL_SET,
+ ECORE_TIMER_SUB_ID_INTERVAL_GET,
+ ECORE_TIMER_SUB_ID_DELAY,
+ ECORE_TIMER_SUB_ID_RESET,
+ ECORE_TIMER_SUB_ID_PENDING_GET,
+ ECORE_TIMER_SUB_ID_LAST,
+};
+
+#define ECORE_TIMER_ID(sub_id) (ECORE_TIMER_BASE_ID + sub_id)
+
+/**
+ * @def ecore_timer_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] in
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_timer_constructor(in, func, data) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(double, in), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def ecore_timer_loop_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] in
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_timer_loop_constructor(in, func, data) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_LOOP_CONSTRUCTOR), EO_TYPECHECK(double, in), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def ecore_obj_timer_interval_set
+ * @since 1.8
+ *
+ * Change the interval the timer ticks of.
+ *
+ * @param[in] in
+ *
+ * @see ecore_timer_interval_set
+ */
+#define ecore_obj_timer_interval_set(in) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_INTERVAL_SET), EO_TYPECHECK(double, in)
+
+/**
+ * @def ecore_obj_timer_interval_get
+ * @since 1.8
+ *
+ * Get the interval the timer ticks on.
+ *
+ * @param[out] ret
+ *
+ * @see ecore_timer_interval_get
+ */
+#define ecore_obj_timer_interval_get(ret) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_INTERVAL_GET), EO_TYPECHECK(double *, ret)
+
+/**
+ * @def ecore_obj_timer_delay
+ * @since 1.8
+ *
+ * Add some delay for the next occurrence of a timer.
+ *
+ * @param[in] add
+ *
+ * @see ecore_timer_delay
+ */
+#define ecore_obj_timer_delay(add) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_DELAY), EO_TYPECHECK(double, add)
+
+/**
+ * @def ecore_obj_timer_reset
+ * @since 1.8
+ *
+ * Reset a timer to its full interval.
+ *
+ * @see ecore_timer_reset
+ */
+#define ecore_obj_timer_reset() ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_RESET)
+
+/**
+ * @def ecore_obj_timer_pending_get
+ * @since 1.8
+ *
+ * Get the pending time regarding a timer.
+ *
+ * @param[out] ret
+ *
+ * @see ecore_timer_pending_get
+ */
+#define ecore_obj_timer_pending_get(ret) ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_PENDING_GET), EO_TYPECHECK(double *, ret)
+
+EAPI Ecore_Timer *ecore_timer_add(double in, Ecore_Task_Cb func, const void *data);
+EAPI Ecore_Timer *ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data);
+EAPI void *ecore_timer_del(Ecore_Timer *timer);
+EAPI void ecore_timer_interval_set(Ecore_Timer *timer, double in);
+EAPI double ecore_timer_interval_get(Ecore_Timer *timer);
+EAPI void ecore_timer_freeze(Ecore_Timer *timer);
+EAPI void ecore_timer_thaw(Ecore_Timer *timer);
+EAPI void ecore_timer_delay(Ecore_Timer *timer, double add);
+EAPI void ecore_timer_reset(Ecore_Timer *timer);
+EAPI double ecore_timer_pending_get(Ecore_Timer *timer);
+EAPI double ecore_timer_precision_get(void);
+EAPI void ecore_timer_precision_set(double precision);
+EAPI char *ecore_timer_dump(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Idle_Group Ecore Idle functions
+ *
+ * The idler functionality in Ecore allows for callbacks to be called when the
+ * program isn't handling @ref Ecore_Event_Group "events", @ref Ecore_Timer_Group
+ * "timers" or @ref Ecore_FD_Handler_Group "fd handlers".
+ *
+ * There are three types of idlers: Enterers, Idlers(proper) and Exiters. They
+ * are called, respectively, when the program is about to enter an idle state,
+ * when the program is in an idle state and when the program has just left an
+ * idle state and will begin processing @ref Ecore_Event_Group "events", @ref
+ * Ecore_Timer_Group "timers" or @ref Ecore_FD_Handler_Group "fd handlers".
+ *
+ * Enterer callbacks are good for updating your program's state, if
+ * it has a state engine. Once all of the enterer handlers are
+ * called, the program will enter a "sleeping" state.
+ *
+ * Idler callbacks are called when the main loop has called all
+ * enterer handlers. They are useful for interfaces that require
+ * polling and timers would be too slow to use.
+ *
+ * Exiter callbacks are called when the main loop wakes up from an idle state.
+ *
+ * If no idler callbacks are specified, then the process literally
+ * goes to sleep. Otherwise, the idler callbacks are called
+ * continuously while the loop is "idle", using as much CPU as is
+ * available to the process.
+ *
+ * @note Idle state doesn't mean that the @b program is idle, but
+ * that the <b>main loop</b> is idle. It doesn't have any timers,
+ * events, fd handlers or anything else to process (which in most
+ * <em>event driven</em> programs also means that the @b program is
+ * idle too, but it's not a rule). The program itself may be doing
+ * a lot of processing in the idler, or in another thread, for
+ * example.
+ *
+ * Example with functions that deal with idle state:
+ *
+ * @li @ref ecore_idler_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/*
+ * @since 1.8
+ */
+typedef Eo Ecore_Idler; /**< A handle for idlers */
+#define ECORE_IDLER_CLASS ecore_idler_class_get()
+const Eo_Class *ecore_idler_class_get(void) EINA_CONST;
+
+extern EAPI Eo_Op ECORE_IDLER_BASE_ID;
+
+enum
+{
+ ECORE_IDLER_SUB_ID_CONSTRUCTOR,
+ ECORE_IDLER_SUB_ID_LAST
+};
+
+#define ECORE_IDLER_ID(sub_id) (ECORE_IDLER_BASE_ID + sub_id)
+
+/**
+ * @def ecore_idler_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_idler_constructor(func, data) ECORE_IDLER_ID(ECORE_IDLER_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ *
+ */
+
+typedef Eo Ecore_Idle_Enterer; /**< A handle for idle enterers */
+#define ECORE_IDLE_ENTERER_CLASS ecore_idle_enterer_class_get()
+const Eo_Class *ecore_idle_enterer_class_get(void) EINA_CONST;
+
+extern EAPI Eo_Op ECORE_IDLE_ENTERER_BASE_ID;
+
+enum
+{
+ ECORE_IDLE_ENTERER_SUB_ID_AFTER_CONSTRUCTOR,
+ ECORE_IDLE_ENTERER_SUB_ID_BEFORE_CONSTRUCTOR,
+ ECORE_IDLE_ENTERER_SUB_ID_LAST
+};
+
+#define ECORE_IDLE_ENTERER_ID(sub_id) (ECORE_IDLE_ENTERER_BASE_ID + sub_id)
+
+/**
+ * @def ecore_idle_enterer_after_constructor
+ * @since 1.8
+ *
+ * Contructor. Will insert the handler at the end of the list.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_idle_enterer_after_constructor(func, data) ECORE_IDLE_ENTERER_ID(ECORE_IDLE_ENTERER_SUB_ID_AFTER_CONSTRUCTOR), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * @def ecore_idle_enterer_before_constructor
+ * @since 1.8
+ *
+ * Contructor. Will insert the handler at the beginning of the list.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_idle_enterer_before_constructor(func, data) ECORE_IDLE_ENTERER_ID(ECORE_IDLE_ENTERER_SUB_ID_BEFORE_CONSTRUCTOR), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ *
+ */
+
+/*
+ * @since 1.8
+ */
+typedef Eo Ecore_Idle_Exiter; /**< A handle for idle exiters */
+#define ECORE_IDLE_EXITER_CLASS ecore_idle_exiter_class_get()
+const Eo_Class *ecore_idle_exiter_class_get(void) EINA_CONST;
+
+extern EAPI Eo_Op ECORE_IDLE_EXITER_BASE_ID;
+
+enum
+{
+ ECORE_IDLE_EXITER_SUB_ID_CONSTRUCTOR,
+ ECORE_IDLE_EXITER_SUB_ID_LAST
+};
+
+#define ECORE_IDLE_EXITER_ID(sub_id) (ECORE_IDLE_EXITER_BASE_ID + sub_id)
+
+/**
+ * @def ecore_idle_exiter_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_idle_exiter_constructor(func, data) ECORE_IDLE_EXITER_ID(ECORE_IDLE_EXITER_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(Ecore_Task_Cb, func), EO_TYPECHECK(const void *, data)
+
+/**
+ * Add an idler handler.
+ * @param func The function to call when idling.
+ * @param data The data to be passed to this @p func call.
+ * @return A idler handle if successfully added, @c NULL otherwise.
+ *
+ * Add an idler handle to the event loop, returning a handle on
+ * success and @c NULL otherwise. The function @p func will be called
+ * repeatedly while no other events are ready to be processed, as
+ * long as it returns @c 1 (or ECORE_CALLBACK_RENEW). A return of @c 0
+ * (or ECORE_CALLBACK_CANCEL) deletes the idler.
+ *
+ * Idlers are useful for progressively prossessing data without blocking.
+ */
+EAPI Ecore_Idler *ecore_idler_add(Ecore_Task_Cb func, const void *data);
+
+/**
+ * Delete an idler callback from the list to be executed.
+ * @param idler The handle of the idler callback to delete
+ * @return The data pointer passed to the idler callback on success, @c NULL
+ * otherwise.
+ */
+EAPI void *ecore_idler_del(Ecore_Idler *idler);
+
+EAPI Ecore_Idle_Enterer *ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data);
+EAPI Ecore_Idle_Enterer *ecore_idle_enterer_before_add(Ecore_Task_Cb func, const void *data);
+EAPI void *ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer);
+
+EAPI Ecore_Idle_Exiter *ecore_idle_exiter_add(Ecore_Task_Cb func, const void *data);
+EAPI void *ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Thread_Group Ecore Thread functions
+ *
+ * Facilities to run heavy tasks in different threads to avoid blocking
+ * the main loop.
+ *
+ * The EFL is, for the most part, not thread safe. This means that if you
+ * have some task running in another thread and you have, for example, an
+ * Evas object to show the status progress of this task, you cannot update
+ * the object from within the thread. This can only be done from the main
+ * thread, the one running the main loop. This problem can be solved
+ * by running a thread that sends messages to the main one using an
+ * @ref Ecore_Pipe_Group "Ecore_Pipe", but when you need to handle other
+ * things like cancelling the thread, your code grows in complexity and gets
+ * much harder to maintain.
+ *
+ * Ecore Thread is here to solve that problem. It is @b not a simple wrapper
+ * around standard POSIX threads (or the equivalent in other systems) and
+ * it's not meant to be used to run parallel tasks throughout the entire
+ * duration of the program, especially when these tasks are performance
+ * critical, as Ecore manages these tasks using a pool of threads based on
+ * system configuration.
+ *
+ * What Ecore Thread does, is make it a lot easier to dispatch a worker
+ * function to perform some heavy task and then get the result once it
+ * completes, without blocking the application's UI. In addition, cancelling
+ * and rescheduling comes practically for free and the developer needs not
+ * worry about how many threads are launched, since Ecore will schedule
+ * them according to the number of processors the system has and maximum
+ * amount of concurrent threads set for the application.
+ *
+ * At the system level, Ecore will start a new thread on an as-needed basis
+ * until the maximum set is reached. When no more threads can be launched,
+ * new worker functions will be queued in a waiting list until a thread
+ * becomes available. This way, system threads will be shared throughout
+ * different worker functions, but running only one at a time. At the same
+ * time, a worker function that is rescheduled may be run on a different
+ * thread the next time.
+ *
+ * The ::Ecore_Thread handler has two meanings, depending on what context
+ * it is on. The one returned when starting a worker with any of the
+ * functions ecore_thread_run() or ecore_thread_feedback_run() is an
+ * identifier of that specific instance of the function and can be used from
+ * the main loop with the ecore_thread_cancel() and ecore_thread_check()
+ * functions. This handler must not be shared with the worker function
+ * function running in the thread. This same handler will be the one received
+ * on the @c end, @c cancel and @c feedback callbacks.
+ *
+ * The worker function, that's the one running in the thread, also receives
+ * an ::Ecore_Thread handler that can be used with ecore_thread_cancel() and
+ *ecore_thread_check(), sharing the flag with the main loop. But this
+ * handler is also associated with the thread where the function is running.
+ * This has strong implications when working with thread local data.
+ *
+ * There are two kinds of worker threads Ecore handles: simple, or short,
+ * workers and feedback workers.
+ *
+ * The first kind is for simple functions that perform a
+ * usually small but time consuming task. Ecore will run this function in
+ * a thread as soon as one becomes available and notify the calling user of
+ * its completion once the task is done.
+ *
+ * The following image shows the flow of a program running four tasks on
+ * a pool of two threads.
+ *
+ * @image html ecore_thread.png
+ * @image rtf ecore_thread.png
+ * @image latex ecore_thread.eps width=\textwidth
+ *
+ * For larger tasks that may require continuous communication with the main
+ * program, the feedback workers provide the same functionality plus a way
+ * for the function running in the thread to send messages to the main
+ * thread.
+ *
+ * The next diagram omits some details shown in the previous one regarding
+ * how threads are spawned and tasks are queued, but illustrates how feedback
+ * jobs communicate with the main loop and the special case of threads
+ * running out of pool.
+ *
+ * @image html ecore_thread_feedback.png
+ * @image rtf ecore_thread_feedback.png
+ * @image latex ecore_thread_feedback.eps width=\textwidth
+ *
+ * See an overview example in @ref ecore_thread_example_c.
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+typedef struct _Ecore_Thread Ecore_Thread; /**< A handle for threaded jobs */
+
+/**
+ * @typedef Ecore_Thread_Cb Ecore_Thread_Cb
+ * A callback used by Ecore_Thread helper.
+ */
+typedef void (*Ecore_Thread_Cb)(void *data, Ecore_Thread *thread);
+/**
+ * @typedef Ecore_Thread_Notify_Cb Ecore_Thread_Notify_Cb
+ * A callback used by the main loop to receive data sent by an
+ * @ref Ecore_Thread_Group.
+ */
+typedef void (*Ecore_Thread_Notify_Cb)(void *data, Ecore_Thread *thread, void *msg_data);
+
+/**
+ * Schedule a task to run in a parallel thread to avoid locking the main loop
+ *
+ * @param func_blocking The function that should run in another thread.
+ * @param func_end Function to call from main loop when @p func_blocking
+ * completes its task successfully (may be NULL)
+ * @param func_cancel Function to call from main loop if the thread running
+ * @p func_blocking is cancelled or fails to start (may be NULL)
+ * @param data User context data to pass to all callbacks.
+ * @return A new thread handler, or @c NULL on failure.
+ *
+ * This function will try to create a new thread to run @p func_blocking in,
+ * or if the maximum number of concurrent threads has been reached, will
+ * add it to the pending list, where it will wait until a thread becomes
+ * available. The return value will be an ::Ecore_Thread handle that can
+ * be used to cancel the thread before its completion.
+ *
+ * @note This function should always return immediately, but in the rare
+ * case that Ecore is built with no thread support, @p func_blocking will
+ * be called here, actually blocking the main loop.
+ *
+ * Once a thread becomes available, @p func_blocking will be run in it until
+ * it finishes, then @p func_end is called from the thread containing the
+ * main loop to inform the user of its completion. While in @p func_blocking,
+ * no functions from the EFL can be used, except for those from Eina that are
+ * marked to be thread-safe. Even for the latter, caution needs to be taken
+ * if the data is shared across several threads.
+ *
+ * @p func_end will be called from the main thread when @p func_blocking ends,
+ * so here it's safe to use anything from the EFL freely.
+ *
+ * The thread can also be cancelled before its completion calling
+ *ecore_thread_cancel(), either from the main thread or @p func_blocking.
+ * In this case, @p func_cancel will be called, also from the main thread
+ * to inform of this happening. If the thread could not be created, this
+ * function will be called and it's @c thread parameter will be NULL. It's
+ * also safe to call any EFL function here, as it will be running in the
+ * main thread.
+ *
+ * Inside @p func_blocking, it's possible to call ecore_thread_reschedule()
+ * to tell Ecore that this function should be called again.
+ *
+ * Be aware that no assumptions can be made about the order in which the
+ * @p func_end callbacks for each task will be called. Once the function is
+ * running in a different thread, it's the OS that will handle its running
+ * schedule, and different functions may take longer to finish than others.
+ * Also remember that just starting several tasks together doesn't mean they
+ * will be running at the same time. Ecore will schedule them based on the
+ * number of threads available for the particular system it's running in,
+ * so some of the jobs started may be waiting until another one finishes
+ * before it can execute its own @p func_blocking.
+ *
+ * @see ecore_thread_feedback_run()
+ * @see ecore_thread_cancel()
+ * @see ecore_thread_reschedule()
+ * @see ecore_thread_max_set()
+ */
+EAPI Ecore_Thread *ecore_thread_run(Ecore_Thread_Cb func_blocking, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data);
+/**
+ * Launch a thread to run a task that can talk back to the main thread
+ *
+ * @param func_heavy The function that should run in another thread.
+ * @param func_notify Function that receives the data sent from the thread
+ * @param func_end Function to call from main loop when @p func_heavy
+ * completes its task successfully
+ * @param func_cancel Function to call from main loop if the thread running
+ * @p func_heavy is cancelled or fails to start
+ * @param data User context data to pass to all callback.
+ * @param try_no_queue If you want to run outside of the thread pool.
+ * @return A new thread handler, or @c NULL on failure.
+ *
+ * See ecore_thread_run() for a general description of this function.
+ *
+ * The difference with the above is that ecore_thread_run() is meant for
+ * tasks that don't need to communicate anything until they finish, while
+ * this function is provided with a new callback, @p func_notify, that will
+ * be called from the main thread for every message sent from @p func_heavy
+ * with ecore_thread_feedback().
+ *
+ * Like with ecore_thread_run(), a new thread will be launched to run
+ * @p func_heavy unless the maximum number of simultaneous threads has been
+ * reached, in which case the function will be scheduled to run whenever a
+ * running task ends and a thread becomes free. But if @p try_no_queue is
+ * set, Ecore will first try to launch a thread outside of the pool to run
+ * the task. If it fails, it will revert to the normal behaviour of using a
+ * thread from the pool as if @p try_no_queue had not been set.
+ *
+ * Keep in mind that Ecore handles the thread pool based on the number of
+ * CPUs available, but running a thread outside of the pool doesn't count for
+ * this, so having too many of them may have drastic effects over the
+ * program's performance.
+ *
+ * @see ecore_thread_feedback()
+ * @see ecore_thread_run()
+ * @see ecore_thread_cancel()
+ * @see ecore_thread_reschedule()
+ * @see ecore_thread_max_set()
+ */
+EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy, Ecore_Thread_Notify_Cb func_notify,
+ Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel,
+ const void *data, Eina_Bool try_no_queue);
+/**
+ * Cancel a running thread.
+ *
+ * @param thread The thread to cancel.
+ * @return Will return @c EINA_TRUE if the thread has been cancelled,
+ * @c EINA_FALSE if it is pending.
+ *
+ * This function can be called both in the main loop or in the running thread.
+ *
+ * This function cancels a running thread. If @p thread can be immediately
+ * cancelled (it's still pending execution after creation or rescheduling),
+ * then the @c cancel callback will be called, @p thread will be freed and
+ * the function will return @c EINA_TRUE.
+ *
+ * If the thread is already running, then this function returns @c EINA_FALSE
+ * after marking the @p thread as pending cancellation. For the thread to
+ * actually be terminated, it needs to return from the user function back
+ * into Ecore control. This can happen in several ways:
+ * @li The function ends and returns normally. If it hadn't been cancelled,
+ * @c func_end would be called here, but instead @c func_cancel will happen.
+ * @li The function returns after requesting to be rescheduled with
+ * ecore_thread_reschedule().
+ * @li The function is prepared to leave early by checking if
+ * ecore_thread_check() returns @c EINA_TRUE.
+ *
+ * The user function can cancel itself by calling ecore_thread_cancel(), but
+ * it should always use the ::Ecore_Thread handle passed to it and never
+ * share it with the main loop thread by means of shared user data or any
+ * other way.
+ *
+ * @p thread will be freed and should not be used again if this function
+ * returns @c EINA_TRUE or after the @c func_cancel callback returns.
+ *
+ * @see ecore_thread_check()
+ */
+EAPI Eina_Bool ecore_thread_cancel(Ecore_Thread *thread);
+/**
+ * Checks if a thread is pending cancellation
+ *
+ * @param thread The thread to test.
+ * @return @c EINA_TRUE if the thread is pending cancellation,
+ * @c EINA_FALSE if it is not.
+ *
+ * This function can be called both in the main loop or in the running thread.
+ *
+ * When ecore_thread_cancel() is called on an already running task, the
+ * thread is marked as pending cancellation. This function returns @c EINA_TRUE
+ * if this mark is set for the given @p thread and can be used from the
+ * main loop thread to check if a still active thread has been cancelled,
+ * or from the user function running in the thread to check if it should
+ * stop doing what it's doing and return early, effectively cancelling the
+ * task.
+ *
+ * @see ecore_thread_cancel()
+ */
+EAPI Eina_Bool ecore_thread_check(Ecore_Thread *thread);
+/**
+ * Sends data from the worker thread to the main loop
+ *
+ * @param thread The current ::Ecore_Thread context to send data from
+ * @param msg_data Data to be transmitted to the main loop
+ * @return @c EINA_TRUE if @p msg_data was successfully sent to main loop,
+ * @c EINA_FALSE if anything goes wrong.
+ *
+ * You should use this function only in the @c func_heavy call.
+ *
+ * Only the address to @p msg_data will be sent and once this function
+ * returns @c EINA_TRUE, the job running in the thread should never touch the
+ * contents of it again. The data sent should be malloc()'ed or something
+ * similar, as long as it's not memory local to the thread that risks being
+ * overwritten or deleted once it goes out of scope or the thread finishes.
+ *
+ * Care must be taken that @p msg_data is properly freed in the @c func_notify
+ * callback set when creating the thread.
+ *
+ * @see ecore_thread_feedback_run()
+ */
+EAPI Eina_Bool ecore_thread_feedback(Ecore_Thread *thread, const void *msg_data);
+/**
+ * Asks for the function in the thread to be called again at a later time
+ *
+ * @param thread The current ::Ecore_Thread context to rescheduled
+ * @return @c EINA_TRUE if the task was successfully rescheduled,
+ * @c EINA_FALSE if anything goes wrong.
+ *
+ * This function should be called only from the same function represented
+ * by @p thread.
+ *
+ * Calling this function will mark the thread for a reschedule, so as soon
+ * as it returns, it will be added to the end of the list of pending tasks.
+ * If no other tasks are waiting or there are sufficient threads available,
+ * the rescheduled task will be launched again immediately.
+ *
+ * This should never return @c EINA_FALSE, unless it was called from the wrong
+ * thread or with the wrong arguments.
+ *
+ * The @c func_end callback set when the thread is created will not be
+ * called until the function in the thread returns without being rescheduled.
+ * Similarly, if the @p thread is cancelled, the reschedule will not take
+ * effect.
+ */
+EAPI Eina_Bool ecore_thread_reschedule(Ecore_Thread *thread);
+/**
+ * Gets the number of active threads running jobs
+ *
+ * @return Number of active threads running jobs
+ *
+ * This returns the number of threads currently running jobs of any type
+ * through the Ecore_Thread API.
+ *
+ * @note Jobs started through the ecore_thread_feedback_run() function with
+ * the @c try_no_queue parameter set to @c EINA_TRUE will not be accounted for
+ * in the return of this function unless the thread creation fails and it
+ * falls back to using one from the pool.
+ */
+EAPI int ecore_thread_active_get(void);
+/**
+ * Gets the number of short jobs waiting for a thread to run
+ *
+ * @return Number of pending threads running "short" jobs
+ *
+ * This returns the number of tasks started with ecore_thread_run() that are
+ * pending, waiting for a thread to become available to run them.
+ */
+EAPI int ecore_thread_pending_get(void);
+/**
+ * Gets the number of feedback jobs waiting for a thread to run
+ *
+ * @return Number of pending threads running "feedback" jobs
+ *
+ * This returns the number of tasks started with ecore_thread_feedback_run()
+ * that are pending, waiting for a thread to become available to run them.
+ */
+EAPI int ecore_thread_pending_feedback_get(void);
+/**
+ * Gets the total number of pending jobs
+ *
+ * @return Number of pending threads running jobs
+ *
+ * Same as the sum of ecore_thread_pending_get() and
+ *ecore_thread_pending_feedback_get().
+ */
+EAPI int ecore_thread_pending_total_get(void);
+/**
+ * Gets the maximum number of threads that can run simultaneously
+ *
+ * @return Max possible number of Ecore_Thread's running concurrently
+ *
+ * This returns the maximum number of Ecore_Thread's that may be running at
+ * the same time. If this number is reached, new jobs started by either
+ *ecore_thread_run() or ecore_thread_feedback_run() will be added to the
+ * respective pending queue until one of the running threads finishes its
+ * task and becomes available to run a new one.
+ *
+ * By default, this will be the number of available CPUs for the
+ * running program (as returned by eina_cpu_count()), or 1 if this value
+ * could not be fetched.
+ *
+ * @see ecore_thread_max_set()
+ * @see ecore_thread_max_reset()
+ */
+EAPI int ecore_thread_max_get(void);
+/**
+ * Sets the maximum number of threads allowed to run simultaneously
+ *
+ * @param num The new maximum
+ *
+ * This sets a new value for the maximum number of concurrently running
+ * Ecore_Thread's. It @b must an integer between 1 and (16 * @c x), where @c x
+ * is the number for CPUs available.
+ *
+ * @see ecore_thread_max_get()
+ * @see ecore_thread_max_reset()
+ */
+EAPI void ecore_thread_max_set(int num);
+/**
+ * Resets the maximum number of concurrently running threads to the default
+ *
+ * This resets the value returned by ecore_thread_max_get() back to its
+ * default.
+ *
+ * @see ecore_thread_max_get()
+ * @see ecore_thread_max_set()
+ */
+EAPI void ecore_thread_max_reset(void);
+/**
+ * Gets the number of threads available for running tasks
+ *
+ * @return The number of available threads
+ *
+ * Same as doing ecore_thread_max_get() - ecore_thread_active_get().
+ *
+ * This function may return a negative number only in the case the user
+ * changed the maximum number of running threads while other tasks are
+ * running.
+ */
+EAPI int ecore_thread_available_get(void);
+/**
+ * Adds some data to a hash local to the thread
+ *
+ * @param thread The thread context the data belongs to
+ * @param key The name under which the data will be stored
+ * @param value The data to add
+ * @param cb Function to free the data when removed from the hash
+ * @param direct If true, this will not copy the key string (like
+ * eina_hash_direct_add())
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * Ecore Thread has a mechanism to share data across several worker functions
+ * that run on the same system thread. That is, the data is stored per
+ * thread and for a worker function to have access to it, it must be run
+ * by the same thread that stored the data.
+ *
+ * When there are no more workers pending, the thread will be destroyed
+ * along with the internal hash and any data left in it will be freed with
+ * the @p cb function given.
+ *
+ * This set of functions is useful to share things around several instances
+ * of a function when that thing is costly to create and can be reused, but
+ * may only be used by one function at a time.
+ *
+ * For example, if you have a program doing requisitions to a database,
+ * these requisitions can be done in threads so that waiting for the
+ * database to respond doesn't block the UI. Each of these threads will
+ * run a function, and each function will be dependent on a connection to
+ * the database, which may not be able to handle more than one request at
+ * a time so for each running function you will need one connection handle.
+ * The options then are:
+ * @li Each function opens a connection when it's called, does the work and
+ * closes the connection when it finishes. This may be costly, wasting a lot
+ * of time on resolving hostnames, negotiating permissions and allocating
+ * memory.
+ * @li Open the connections in the main loop and pass it to the threads
+ * using the data pointer. Even worse, it's just as costly as before and now
+ * it may even be kept with connections open doing nothing until a thread
+ * becomes available to run the function.
+ * @li Have a way to share connection handles, so that each instance of the
+ * function can check if an available connection exists, and if it doesn't,
+ * create one and add it to the pool. When no more connections are needed,
+ * they are all closed.
+ *
+ * The last option is the most efficient, but it requires a lot of work to
+ * implement properly. Using thread local data helps to achieve the same
+ * result while avoiding doing all the tracking work on your code. The way
+ * to use it would be, at the worker function, to ask for the connection
+ * with ecore_thread_local_data_find() and if it doesn't exist, then open
+ * a new one and save it with ecore_thread_local_data_add(). Do the work and
+ * forget about the connection handle, when everything is done the function
+ * just ends. The next worker to run on that thread will check if a
+ * connection exists and find that it does, so the process of opening a
+ * new one has been spared. When no more workers exist, the thread is
+ * destroyed and the callback used when saving the connection will be called
+ * to close it.
+ *
+ * This function adds the data @p value to the thread data under the given
+ * @p key.
+ * No other value in the hash may have the same @p key. If you need to
+ * change the value under a @p key, or you don't know if one exists already,
+ * you can use ecore_thread_local_data_set().
+ *
+ * Neither @p key nor @p value may be @c NULL and @p key will be copied in the
+ * hash, unless @p direct is set, in which case the string used should not
+ * be freed until the data is removed from the hash.
+ *
+ * The @p cb function will be called when the data in the hash needs to be
+ * freed, be it because it got deleted with ecore_thread_local_data_del() or
+ * because @p thread was terminated and the hash destroyed. This parameter
+ * may be NULL, in which case @p value needs to be manually freed after
+ * removing it from the hash with either ecore_thread_local_data_del() or
+ * ecore_thread_local_data_set(), but it's very unlikely that this is what
+ * you want.
+ *
+ * This function, and all of the others in the @c ecore_thread_local_data
+ * family of functions, can only be called within the worker function running
+ * in the thread. Do not call them from the main loop or from a thread
+ * other than the one represented by @p thread.
+ *
+ * @see ecore_thread_local_data_set()
+ * @see ecore_thread_local_data_find()
+ * @see ecore_thread_local_data_del()
+ */
+EAPI Eina_Bool ecore_thread_local_data_add(Ecore_Thread *thread, const char *key, void *value,
+ Eina_Free_Cb cb, Eina_Bool direct);
+/**
+ * Sets some data in the hash local to the given thread
+ *
+ * @param thread The thread context the data belongs to
+ * @param key The name under which the data will be stored
+ * @param value The data to add
+ * @param cb Function to free the data when removed from the hash
+ *
+ * If no data exists in the hash under the @p key, this function adds
+ * @p value in the hash under the given @p key and returns NULL.
+ * The key itself is copied.
+ *
+ * If the hash already contains something under @p key, the data will be
+ * replaced by @p value and the old value will be returned.
+ *
+ * @c NULL will also be returned if either @p key or @p value are @c NULL, or
+ * if an error occurred.
+ *
+ * This function, and all of the others in the @c ecore_thread_local_data
+ * family of functions, can only be called within the worker function running
+ * in the thread. Do not call them from the main loop or from a thread
+ * other than the one represented by @p thread.
+ *
+ * @see ecore_thread_local_data_add()
+ * @see ecore_thread_local_data_del()
+ * @see ecore_thread_local_data_find()
+ */
+EAPI void *ecore_thread_local_data_set(Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb);
+/**
+ * Gets data stored in the hash local to the given thread
+ *
+ * @param thread The thread context the data belongs to
+ * @param key The name under which the data is stored
+ * @return The value under the given key, or @c NULL on error.
+ *
+ * Finds and return the data stored in the shared hash under the key @p key.
+ *
+ * This function, and all of the others in the @c ecore_thread_local_data
+ * family of functions, can only be called within the worker function running
+ * in the thread. Do not call them from the main loop or from a thread
+ * other than the one represented by @p thread.
+ *
+ * @see ecore_thread_local_data_add()
+ * @see ecore_thread_local_data_wait()
+ */
+EAPI void *ecore_thread_local_data_find(Ecore_Thread *thread, const char *key);
+/**
+ * Deletes from the thread's hash the data corresponding to the given key
+ *
+ * @param thread The thread context the data belongs to
+ * @param key The name under which the data is stored
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * If there's any data stored associated with @p key in the global hash,
+ * this function will remove it from it and return @c EINA_TRUE. If no data
+ * exists or an error occurs, it returns @c EINA_FALSE.
+ *
+ * If the data was added to the hash with a free function, then it will
+ * also be freed after removing it from the hash, otherwise it requires
+ * to be manually freed by the user, which means that if no other reference
+ * to it exists before calling this function, it will result in a memory
+ * leak.
+ *
+ * This function, and all of the others in the @c ecore_thread_local_data
+ * family of functions, can only be called within the worker function running
+ * in the thread. Do not call them from the main loop or from a thread
+ * other than the one represented by @p thread.
+ *
+ * @see ecore_thread_local_data_add()
+ */
+EAPI Eina_Bool ecore_thread_local_data_del(Ecore_Thread *thread, const char *key);
+
+/**
+ * Adds some data to a hash shared by all threads
+ *
+ * @param key The name under which the data will be stored
+ * @param value The data to add
+ * @param cb Function to free the data when removed from the hash
+ * @param direct If true, this will not copy the key string (like
+ * eina_hash_direct_add())
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * Ecore Thread keeps a hash that can be used to share data across several
+ * threads, including the main loop one, without having to manually handle
+ * mutexes to do so safely.
+ *
+ * This function adds the data @p value to this hash under the given @p key.
+ * No other value in the hash may have the same @p key. If you need to
+ * change the value under a @p key, or you don't know if one exists already,
+ * you can use ecore_thread_global_data_set().
+ *
+ * Neither @p key nor @p value may be @c NULL and @p key will be copied in the
+ * hash, unless @p direct is set, in which case the string used should not
+ * be freed until the data is removed from the hash.
+ *
+ * The @p cb function will be called when the data in the hash needs to be
+ * freed, be it because it got deleted with ecore_thread_global_data_del() or
+ * because Ecore Thread was shut down and the hash destroyed. This parameter
+ * may be NULL, in which case @p value needs to be manually freed after
+ * removing it from the hash with either ecore_thread_global_data_del() or
+ *ecore_thread_global_data_set().
+ *
+ * Manually freeing any data that was added to the hash with a @p cb function
+ * is likely to produce a segmentation fault, or any other strange
+ * happenings, later on in the program.
+ *
+ * @see ecore_thread_global_data_del()
+ * @see ecore_thread_global_data_set()
+ * @see ecore_thread_global_data_find()
+ */
+EAPI Eina_Bool ecore_thread_global_data_add(const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct);
+/**
+ * Sets some data in the hash shared by all threads
+ *
+ * @param key The name under which the data will be stored
+ * @param value The data to add
+ * @param cb Function to free the data when removed from the hash
+ *
+ * If no data exists in the hash under the @p key, this function adds
+ * @p value in the hash under the given @p key and returns NULL.
+ * The key itself is copied.
+ *
+ * If the hash already contains something under @p key, the data will be
+ * replaced by @p value and the old value will be returned.
+ *
+ * @c NULL will also be returned if either @p key or @p value are @c NULL, or
+ * if an error occurred.
+ *
+ * @see ecore_thread_global_data_add()
+ * @see ecore_thread_global_data_del()
+ * @see ecore_thread_global_data_find()
+ */
+EAPI void *ecore_thread_global_data_set(const char *key, void *value, Eina_Free_Cb cb);
+/**
+ * Gets data stored in the hash shared by all threads
+ *
+ * @param key The name under which the data is stored
+ * @return The value under the given key, or @c NULL on error.
+ *
+ * Finds and return the data stored in the shared hash under the key @p key.
+ *
+ * Keep in mind that the data returned may be used by more than one thread
+ * at the same time and no reference counting is done on it by Ecore.
+ * Freeing the data or modifying its contents may require additional
+ * precautions to be considered, depending on the application's design.
+ *
+ * @see ecore_thread_global_data_add()
+ * @see ecore_thread_global_data_wait()
+ */
+EAPI void *ecore_thread_global_data_find(const char *key);
+/**
+ * Deletes from the shared hash the data corresponding to the given key
+ *
+ * @param key The name under which the data is stored
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * If there's any data stored associated with @p key in the global hash,
+ * this function will remove it from it and return @c EINA_TRUE. If no data
+ * exists or an error occurs, it returns @c EINA_FALSE.
+ *
+ * If the data was added to the hash with a free function, then it will
+ * also be freed after removing it from the hash, otherwise it requires
+ * to be manually freed by the user, which means that if no other reference
+ * to it exists before calling this function, it will result in a memory
+ * leak.
+ *
+ * Note, also, that freeing data that other threads may be using will result
+ * in a crash, so appropriate care must be taken by the application when
+ * that possibility exists.
+ *
+ * @see ecore_thread_global_data_add()
+ */
+EAPI Eina_Bool ecore_thread_global_data_del(const char *key);
+/**
+ * Gets data stored in the shared hash, or wait for it if it doesn't exist
+ *
+ * @param key The name under which the data is stored
+ * @param seconds The amount of time in seconds to wait for the data.
+ * @return The value under the given key, or @c NULL on error.
+ *
+ * Finds and return the data stored in the shared hash under the key @p key.
+ *
+ * If there's nothing in the hash under the given @p key, the function
+ * will block and wait up to @p seconds seconds for some other thread to
+ * add it with either ecore_thread_global_data_add() or
+ * ecore_thread_global_data_set(). If after waiting there's still no data
+ * to get, @c NULL will be returned.
+ *
+ * If @p seconds is 0, then no waiting will happen and this function works
+ * like ecore_thread_global_data_find(). If @p seconds is less than 0, then
+ * the function will wait indefinitely.
+ *
+ * Keep in mind that the data returned may be used by more than one thread
+ * at the same time and no reference counting is done on it by Ecore.
+ * Freeing the data or modifying its contents may require additional
+ * precautions to be considered, depending on the application's design.
+ *
+ * @see ecore_thread_global_data_add()
+ * @see ecore_thread_global_data_find()
+ */
+EAPI void *ecore_thread_global_data_wait(const char *key, double seconds);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Pipe_Group Pipe wrapper
+ *
+ * These functions wrap the pipe / write / read functions to easily
+ * integrate its use into ecore's main loop.
+ *
+ * The ecore_pipe_add() function creates file descriptors (sockets
+ * on Windows) and attach a handle to the ecore main loop. That
+ * handle is called when data is read in the pipe. To write data in
+ * the pipe, just call ecore_pipe_write(). When you are done, just
+ * call ecore_pipe_del().
+ *
+ * For examples see here:
+ * @li @ref tutorial_ecore_pipe_gstreamer_example
+ * @li @ref tutorial_ecore_pipe_simple_example
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+typedef struct _Ecore_Pipe Ecore_Pipe; /**< A handle for pipes */
+
+/**
+ * @typedef Ecore_Pipe_Cb Ecore_Pipe_Cb
+ * The callback that data written to the pipe is sent to.
+ */
+typedef void (*Ecore_Pipe_Cb)(void *data, void *buffer, unsigned int nbyte);
+
+EAPI Ecore_Pipe *ecore_pipe_add(Ecore_Pipe_Cb handler, const void *data);
+EAPI void *ecore_pipe_del(Ecore_Pipe *p);
+EAPI Eina_Bool ecore_pipe_write(Ecore_Pipe *p, const void *buffer, unsigned int nbytes);
+EAPI void ecore_pipe_write_close(Ecore_Pipe *p);
+EAPI void ecore_pipe_read_close(Ecore_Pipe *p);
+EAPI void ecore_pipe_thaw(Ecore_Pipe *p);
+EAPI void ecore_pipe_freeze(Ecore_Pipe *p);
+EAPI int ecore_pipe_wait(Ecore_Pipe *p, int message_count, double wait);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Job_Group Ecore Job functions
+ *
+ * You can queue jobs that are to be done by the main loop when the
+ * current event is dealt with.
+ *
+ * Jobs are processed by the main loop similarly to events. They
+ * also will be executed in the order in which they were added.
+ *
+ * A good use for them is when you don't want to execute an action
+ * immediately, but want to give the control back to the main loop
+ * so that it will call your job callback when jobs start being
+ * processed (and if there are other jobs added before yours, they
+ * will be processed first). This also gives the chance to other
+ * actions in your program to cancel the job before it is started.
+ *
+ * Examples of using @ref Ecore_Job :
+ * @li @ref ecore_job_example_c
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/*
+ * @since 1.8
+ */
+typedef Eo Ecore_Job; /**< A job handle */
+#define ECORE_JOB_CLASS ecore_job_class_get()
+const Eo_Class *ecore_job_class_get(void) EINA_CONST;
+
+extern EAPI Eo_Op ECORE_JOB_BASE_ID;
+
+enum
+{
+ ECORE_JOB_SUB_ID_CONSTRUCTOR,
+ ECORE_JOB_SUB_ID_LAST
+};
+
+#define ECORE_JOB_ID(sub_id) (ECORE_JOB_BASE_ID + sub_id)
+
+/**
+ * @def ecore_job_constructor
+ * @since 1.8
+ *
+ * Contructor.
+ *
+ * @param[in] func
+ * @param[in] data
+ *
+ */
+#define ecore_job_constructor(func, data) ECORE_JOB_ID(ECORE_JOB_SUB_ID_CONSTRUCTOR), EO_TYPECHECK(Ecore_Cb, func), EO_TYPECHECK(const void *, data)
+
+EAPI Ecore_Job *ecore_job_add(Ecore_Cb func, const void *data);
+EAPI void *ecore_job_del(Ecore_Job *job);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Application_Group Ecore Application functions
+ *
+ * @{
+ */
+
+EAPI void ecore_app_args_set(int argc, const char **argv);
+EAPI void ecore_app_args_get(int *argc, char ***argv);
+EAPI void ecore_app_restart(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Throttle_Group Ecore Throttle functions
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+EAPI void ecore_throttle_adjust(double amount);
+EAPI double ecore_throttle_get(void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/lib/ecore/Ecore_Getopt.h b/src/lib/ecore/Ecore_Getopt.h
new file mode 100644
index 0000000000..0a11787d4d
--- /dev/null
+++ b/src/lib/ecore/Ecore_Getopt.h
@@ -0,0 +1,419 @@
+#ifndef _ECORE_GETOPT_H
+#define _ECORE_GETOPT_H
+
+#include <stdio.h>
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore_Getopt.h
+ * @brief Contains powerful getopt replacement.
+ *
+ * This replacement handles both short (-X) or long options (--ABC)
+ * options, with various actions supported, like storing one value and
+ * already converting to required type, counting number of
+ * occurrences, setting true or false values, show help, license,
+ * copyright and even support user-defined callbacks.
+ *
+ * It is provided a set of C Pre Processor macros so definition is
+ * straightforward.
+ *
+ * Values will be stored elsewhere indicated by an array of pointers
+ * to values, it is given in separate to parser description so you can
+ * use multiple values with the same parser.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ ECORE_GETOPT_ACTION_STORE,
+ ECORE_GETOPT_ACTION_STORE_CONST,
+ ECORE_GETOPT_ACTION_STORE_TRUE,
+ ECORE_GETOPT_ACTION_STORE_FALSE,
+ ECORE_GETOPT_ACTION_CHOICE,
+ ECORE_GETOPT_ACTION_APPEND,
+ ECORE_GETOPT_ACTION_COUNT,
+ ECORE_GETOPT_ACTION_CALLBACK,
+ ECORE_GETOPT_ACTION_HELP,
+ ECORE_GETOPT_ACTION_VERSION,
+ ECORE_GETOPT_ACTION_COPYRIGHT,
+ ECORE_GETOPT_ACTION_LICENSE
+} Ecore_Getopt_Action;
+
+typedef enum {
+ ECORE_GETOPT_TYPE_STR,
+ ECORE_GETOPT_TYPE_BOOL,
+ ECORE_GETOPT_TYPE_SHORT,
+ ECORE_GETOPT_TYPE_INT,
+ ECORE_GETOPT_TYPE_LONG,
+ ECORE_GETOPT_TYPE_USHORT,
+ ECORE_GETOPT_TYPE_UINT,
+ ECORE_GETOPT_TYPE_ULONG,
+ ECORE_GETOPT_TYPE_DOUBLE
+} Ecore_Getopt_Type;
+
+typedef enum {
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO = 0,
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES = 1,
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL = 3
+} Ecore_Getopt_Desc_Arg_Requirement;
+
+typedef union _Ecore_Getopt_Value Ecore_Getopt_Value;
+
+typedef struct _Ecore_Getopt_Desc_Store Ecore_Getopt_Desc_Store;
+typedef struct _Ecore_Getopt_Desc_Callback Ecore_Getopt_Desc_Callback;
+typedef struct _Ecore_Getopt_Desc Ecore_Getopt_Desc;
+typedef struct _Ecore_Getopt Ecore_Getopt;
+
+union _Ecore_Getopt_Value
+{
+ char **strp;
+ unsigned char *boolp;
+ short *shortp;
+ int *intp;
+ long *longp;
+ unsigned short *ushortp;
+ unsigned int *uintp;
+ unsigned long *ulongp;
+ double *doublep;
+ Eina_List **listp;
+ void **ptrp;
+};
+
+struct _Ecore_Getopt_Desc_Store
+{
+ Ecore_Getopt_Type type; /**< type of data being handled */
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ union
+ {
+ const char *strv;
+ Eina_Bool boolv;
+ short shortv;
+ int intv;
+ long longv;
+ unsigned short ushortv;
+ unsigned int uintv;
+ unsigned long ulongv;
+ double doublev;
+ } def;
+};
+
+struct _Ecore_Getopt_Desc_Callback
+{
+ Eina_Bool (*func)(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ const char *str,
+ void *data,
+ Ecore_Getopt_Value *storage);
+ const void *data;
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ const char *def;
+};
+
+struct _Ecore_Getopt_Desc
+{
+ char shortname; /**< used with a single dash */
+ const char *longname; /**< used with double dashes */
+ const char *help; /**< used by --help/ecore_getopt_help() */
+ const char *metavar; /**< used by ecore_getopt_help() with nargs > 0 */
+
+ Ecore_Getopt_Action action; /**< define how to handle it */
+ union
+ {
+ const Ecore_Getopt_Desc_Store store;
+ const void *store_const;
+ const char *const *choices; /* NULL terminated. */
+ const Ecore_Getopt_Type append_type;
+ const Ecore_Getopt_Desc_Callback callback;
+ const void *dummy;
+ } action_param;
+};
+
+struct _Ecore_Getopt
+{
+ const char *prog; /**< to be used when ecore_app_args_get() fails */
+ const char *usage; /**< usage example, %prog is replaced */
+ const char *version; /**< if exists, --version will work */
+ const char *copyright; /**< if exists, --copyright will work */
+ const char *license; /**< if exists, --license will work */
+ const char *description; /**< long description, possible multiline */
+ Eina_Bool strict : 1; /**< fail on errors */
+ const Ecore_Getopt_Desc descs[]; /* NULL terminated. */
+};
+
+#define ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type, arg_requirement, default_value) \
+ {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_STORE, \
+ {.store = {type, arg_requirement, default_value}}}
+
+#define ECORE_GETOPT_STORE(shortname, longname, help, type) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type, \
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {})
+
+#define ECORE_GETOPT_STORE_STR(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_STR)
+#define ECORE_GETOPT_STORE_BOOL(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_BOOL)
+#define ECORE_GETOPT_STORE_SHORT(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_SHORT)
+#define ECORE_GETOPT_STORE_INT(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_INT)
+#define ECORE_GETOPT_STORE_LONG(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_LONG)
+#define ECORE_GETOPT_STORE_USHORT(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_USHORT)
+#define ECORE_GETOPT_STORE_UINT(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_UINT)
+#define ECORE_GETOPT_STORE_ULONG(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_ULONG)
+#define ECORE_GETOPT_STORE_DOUBLE(shortname, longname, help) \
+ ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_DOUBLE)
+
+#define ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, type) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type, \
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {})
+
+#define ECORE_GETOPT_STORE_METAVAR_STR(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_STR)
+#define ECORE_GETOPT_STORE_METAVAR_BOOL(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_BOOL)
+#define ECORE_GETOPT_STORE_METAVAR_SHORT(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_SHORT)
+#define ECORE_GETOPT_STORE_METAVAR_INT(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_INT)
+#define ECORE_GETOPT_STORE_METAVAR_LONG(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_LONG)
+#define ECORE_GETOPT_STORE_METAVAR_USHORT(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_USHORT)
+#define ECORE_GETOPT_STORE_METAVAR_UINT(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_UINT)
+#define ECORE_GETOPT_STORE_METAVAR_ULONG(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_ULONG)
+#define ECORE_GETOPT_STORE_METAVAR_DOUBLE(shortname, longname, help, metavar) \
+ ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_DOUBLE)
+
+#define ECORE_GETOPT_STORE_DEF(shortname, longname, help, type, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type, \
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL, \
+ default_value)
+
+#define ECORE_GETOPT_STORE_DEF_STR(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_STR, \
+ {.strv = default_value})
+#define ECORE_GETOPT_STORE_DEF_BOOL(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_BOOL, \
+ {.boolv = default_value})
+#define ECORE_GETOPT_STORE_DEF_SHORT(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_SHORT, \
+ {.shortv = default_value})
+#define ECORE_GETOPT_STORE_DEF_INT(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_INT, \
+ {.intv = default_value})
+#define ECORE_GETOPT_STORE_DEF_LONG(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_LONG, \
+ {.longv = default_value})
+#define ECORE_GETOPT_STORE_DEF_USHORT(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_USHORT, \
+ {.ushortv = default_value})
+#define ECORE_GETOPT_STORE_DEF_UINT(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_UINT, \
+ {.uintv = default_value})
+#define ECORE_GETOPT_STORE_DEF_ULONG(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_ULONG, \
+ {.ulongv = default_value})
+#define ECORE_GETOPT_STORE_DEF_DOUBLE(shortname, longname, help, default_value) \
+ ECORE_GETOPT_STORE_DEF(shortname, longname, help, \
+ ECORE_GETOPT_TYPE_DOUBLE, \
+ {.doublev = default_value})
+
+#define ECORE_GETOPT_STORE_FULL_STR(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_STR, \
+ arg_requirement, \
+ {.strv = default_value})
+#define ECORE_GETOPT_STORE_FULL_BOOL(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_BOOL, \
+ arg_requirement, \
+ {.boolv = default_value})
+#define ECORE_GETOPT_STORE_FULL_SHORT(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_SHORT, \
+ arg_requirement, \
+ {.shortv = default_value})
+#define ECORE_GETOPT_STORE_FULL_INT(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_INT, \
+ arg_requirement, \
+ {.intv = default_value})
+#define ECORE_GETOPT_STORE_FULL_LONG(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_LONG, \
+ arg_requirement, \
+ {.longv = default_value})
+#define ECORE_GETOPT_STORE_FULL_USHORT(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_USHORT, \
+ arg_requirement, \
+ {.ushortv = default_value})
+#define ECORE_GETOPT_STORE_FULL_UINT(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_UINT, \
+ arg_requirement, \
+ {.uintv = default_value})
+#define ECORE_GETOPT_STORE_FULL_ULONG(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_ULONG, \
+ arg_requirement, \
+ {.ulongv = default_value})
+#define ECORE_GETOPT_STORE_FULL_DOUBLE(shortname, longname, help, metavar, arg_requirement, default_value) \
+ ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \
+ ECORE_GETOPT_TYPE_DOUBLE, \
+ arg_requirement, \
+ {.doublev = default_value})
+
+#define ECORE_GETOPT_STORE_CONST(shortname, longname, help, value) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_CONST, \
+ {.store_const = value}}
+#define ECORE_GETOPT_STORE_TRUE(shortname, longname, help) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_TRUE, \
+ {.dummy = NULL}}
+#define ECORE_GETOPT_STORE_FALSE(shortname, longname, help) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_FALSE, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_CHOICE(shortname, longname, help, choices_array) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_CHOICE, \
+ {.choices = choices_array}}
+#define ECORE_GETOPT_CHOICE_METAVAR(shortname, longname, help, metavar, choices_array) \
+ {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CHOICE, \
+ {.choices = choices_array}}
+
+#define ECORE_GETOPT_APPEND(shortname, longname, help, sub_type) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_APPEND, \
+ {.append_type = sub_type}}
+#define ECORE_GETOPT_APPEND_METAVAR(shortname, longname, help, metavar, type) \
+ {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_APPEND, \
+ {.append_type = type}}
+
+#define ECORE_GETOPT_COUNT(shortname, longname, help) \
+ {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_COUNT, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar, callback_func, callback_data, argument_requirement, default_value) \
+ {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CALLBACK, \
+ {.callback = {callback_func, callback_data, \
+ argument_requirement, default_value}}}
+#define ECORE_GETOPT_CALLBACK_NOARGS(shortname, longname, help, callback_func, callback_data) \
+ ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, NULL, \
+ callback_func, callback_data, \
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO, \
+ NULL)
+#define ECORE_GETOPT_CALLBACK_ARGS(shortname, longname, help, metavar, callback_func, callback_data) \
+ ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar, \
+ callback_func, callback_data, \
+ ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, \
+ NULL)
+
+#define ECORE_GETOPT_HELP(shortname, longname) \
+ {shortname, longname, "show this message.", NULL, \
+ ECORE_GETOPT_ACTION_HELP, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_VERSION(shortname, longname) \
+ {shortname, longname, "show program version.", NULL, \
+ ECORE_GETOPT_ACTION_VERSION, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_COPYRIGHT(shortname, longname) \
+ {shortname, longname, "show copyright.", NULL, \
+ ECORE_GETOPT_ACTION_COPYRIGHT, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_LICENSE(shortname, longname) \
+ {shortname, longname, "show license.", NULL, \
+ ECORE_GETOPT_ACTION_LICENSE, \
+ {.dummy = NULL}}
+
+#define ECORE_GETOPT_SENTINEL {0, NULL, NULL, NULL, 0, {.dummy = NULL}}
+
+#define ECORE_GETOPT_VALUE_STR(val) {.strp = &(val)}
+#define ECORE_GETOPT_VALUE_BOOL(val) {.boolp = &(val)}
+#define ECORE_GETOPT_VALUE_SHORT(val) {.shortp = &(val)}
+#define ECORE_GETOPT_VALUE_INT(val) {.intp = &(val)}
+#define ECORE_GETOPT_VALUE_LONG(val) {.longp = &(val)}
+#define ECORE_GETOPT_VALUE_USHORT(val) {.ushortp = &(val)}
+#define ECORE_GETOPT_VALUE_UINT(val) {.uintp = &(val)}
+#define ECORE_GETOPT_VALUE_ULONG(val) {.ulongp = &(val)}
+#define ECORE_GETOPT_VALUE_DOUBLE(val) {.doublep = &(val)}
+#define ECORE_GETOPT_VALUE_PTR(val) {.ptrp = &(val)}
+#define ECORE_GETOPT_VALUE_PTR_CAST(val) {.ptrp = (void **)&(val)}
+#define ECORE_GETOPT_VALUE_LIST(val) {.listp = &(val)}
+#define ECORE_GETOPT_VALUE_NONE {.ptrp = NULL}
+
+EAPI void
+ecore_getopt_help(FILE *fp,
+ const Ecore_Getopt *info);
+
+EAPI Eina_Bool
+ ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser);
+EAPI int
+ ecore_getopt_parse(const Ecore_Getopt *parser,
+ Ecore_Getopt_Value *values,
+ int argc,
+ char **argv);
+
+EAPI Eina_List *ecore_getopt_list_free(Eina_List *list);
+
+/* helper functions to be used with ECORE_GETOPT_CALLBACK_*() */
+EAPI Eina_Bool
+ecore_getopt_callback_geometry_parse(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ const char *str,
+ void *data,
+ Ecore_Getopt_Value *storage);
+EAPI Eina_Bool
+ecore_getopt_callback_size_parse(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ const char *str,
+ void *data,
+ Ecore_Getopt_Value *storage);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _ECORE_GETOPT_H */
diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c
new file mode 100644
index 0000000000..3aa15bf77c
--- /dev/null
+++ b/src/lib/ecore/ecore.c
@@ -0,0 +1,878 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+#include <Eina.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+
+
+static Ecore_Version _version = { VMAJ, VMIN, VMIC, VREV };
+EAPI Ecore_Version *ecore_version = &_version;
+
+#define KEEP_MAX(Global, Local) \
+ if (Global < (Local)) \
+ Global = Local;
+
+static Eina_Bool _ecore_memory_statistic(void *data);
+static int _ecore_memory_max_total = 0;
+static int _ecore_memory_max_free = 0;
+static pid_t _ecore_memory_pid = 0;
+#endif
+
+Eo *_ecore_parent = NULL;
+
+static const char *_ecore_magic_string_get(Ecore_Magic m);
+static int _ecore_init_count = 0;
+int _ecore_log_dom = -1;
+int _ecore_fps_debug = 0;
+
+typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
+struct _Ecore_Safe_Call
+{
+ union {
+ Ecore_Cb async;
+ Ecore_Data_Cb sync;
+ } cb;
+ void *data;
+
+ Eina_Lock m;
+ Eina_Condition c;
+
+ int current_id;
+
+ Eina_Bool sync : 1;
+ Eina_Bool suspend : 1;
+};
+
+static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
+static void _thread_safe_cleanup(void *data);
+static void _thread_callback(void *data,
+ void *buffer,
+ unsigned int nbyte);
+static Eina_List *_thread_cb = NULL;
+static Ecore_Pipe *_thread_call = NULL;
+static Eina_Lock _thread_safety;
+static const int wakeup = 42;
+
+static int _thread_loop = 0;
+static Eina_Lock _thread_mutex;
+static Eina_Condition _thread_cond;
+static Eina_Lock _thread_feedback_mutex;
+static Eina_Condition _thread_feedback_cond;
+
+static Eina_Lock _thread_id_lock;
+static int _thread_id = -1;
+static int _thread_id_max = 0;
+static int _thread_id_update = 0;
+
+Eina_Lock _ecore_main_loop_lock;
+int _ecore_main_lock_count;
+
+/** OpenBSD does not define CODESET
+ * FIXME ??
+ */
+
+#ifndef CODESET
+# define CODESET "INVALID"
+#endif
+
+/**
+ * @addtogroup Ecore_Init_Group
+ *
+ * @{
+ */
+
+/**
+ * Set up connections, signal handlers, sockets etc.
+ * @return 1 or greater on success, 0 otherwise
+ *
+ * This function sets up all singal handlers and the basic event loop. If it
+ * succeeds, 1 will be returned, otherwise 0 will be returned.
+ *
+ * @code
+ * #include <Ecore.h>
+ *
+ * int main(int argc, char **argv)
+ * {
+ * if (!ecore_init())
+ * {
+ * printf("ERROR: Cannot init Ecore!\n");
+ * return -1;
+ * }
+ * ecore_main_loop_begin();
+ * ecore_shutdown();
+ * }
+ * @endcode
+ */
+EAPI int
+ecore_init(void)
+{
+ if (++_ecore_init_count != 1)
+ return _ecore_init_count;
+
+ eo_init();
+
+#ifdef HAVE_LOCALE_H
+ setlocale(LC_CTYPE, "");
+#endif
+ /*
+ if (strcmp(nl_langinfo(CODESET), "UTF-8"))
+ {
+ WRN("Not a utf8 locale!");
+ }
+ */
+#ifdef HAVE_EVIL
+ if (!evil_init())
+ return --_ecore_init_count;
+#endif
+ if (!eina_init())
+ goto shutdown_evil;
+ _ecore_log_dom = eina_log_domain_register("ecore", ECORE_DEFAULT_LOG_COLOR);
+ if (_ecore_log_dom < 0)
+ {
+ EINA_LOG_ERR("Ecore was unable to create a log domain.");
+ goto shutdown_log_dom;
+ }
+ if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
+ if (_ecore_fps_debug) _ecore_fps_debug_init();
+ if (!ecore_mempool_init()) goto shutdown_mempool;
+ _ecore_main_loop_init();
+ _ecore_signal_init();
+#ifndef HAVE_EXOTIC
+ _ecore_exe_init();
+#endif
+ _ecore_thread_init();
+ _ecore_glib_init();
+ _ecore_job_init();
+ _ecore_time_init();
+
+ eina_lock_new(&_thread_mutex);
+ eina_condition_new(&_thread_cond, &_thread_mutex);
+ eina_lock_new(&_thread_feedback_mutex);
+ eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
+ _thread_call = _ecore_pipe_add(_thread_callback, NULL);
+ eina_lock_new(&_thread_safety);
+
+ eina_lock_new(&_thread_id_lock);
+
+ eina_lock_new(&_ecore_main_loop_lock);
+
+#if HAVE_MALLINFO
+ if (getenv("ECORE_MEM_STAT"))
+ {
+ _ecore_memory_pid = getpid();
+ ecore_animator_add(_ecore_memory_statistic, NULL);
+ }
+#endif
+
+#if defined(GLIB_INTEGRATION_ALWAYS)
+ if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
+#endif
+ _ecore_parent = eo_add(ECORE_PARENT_CLASS, NULL);
+
+ return _ecore_init_count;
+
+shutdown_mempool:
+ ecore_mempool_shutdown();
+shutdown_log_dom:
+ eina_shutdown();
+shutdown_evil:
+#ifdef HAVE_EVIL
+ evil_shutdown();
+#endif
+
+ eo_shutdown();
+
+ return --_ecore_init_count;
+}
+
+/**
+ * Shut down connections, signal handlers sockets etc.
+ *
+ * @return 0 if ecore shuts down, greater than 0 otherwise.
+ * This function shuts down all things set up in ecore_init() and cleans up all
+ * event queues, handlers, filters, timers, idlers, idle enterers/exiters
+ * etc. set up after ecore_init() was called.
+ *
+ * Do not call this function from any callback that may be called from the main
+ * loop, as the main loop will then fall over and not function properly.
+ */
+EAPI int
+ecore_shutdown(void)
+{
+ Ecore_Pipe *p;
+ /*
+ * take a lock here because _ecore_event_shutdown() does callbacks
+ */
+ _ecore_lock();
+ if (_ecore_init_count <= 0)
+ {
+ ERR("Init count not greater than 0 in shutdown.");
+ _ecore_unlock();
+ return 0;
+ }
+ if (--_ecore_init_count != 0)
+ goto unlock;
+
+ if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
+ _ecore_poller_shutdown();
+ _ecore_animator_shutdown();
+ _ecore_glib_shutdown();
+ _ecore_job_shutdown();
+ _ecore_thread_shutdown();
+
+ /* this looks horrible - a hack for now, but something to note. as
+ * we delete the _thread_call pipe a thread COULD be doing
+ * ecore_pipe_write() or what not to it at the same time - we
+ * must ensure all possible users of this _thread_call are finished
+ * and exited before we delete it here */
+ /*
+ * ok - this causes other valgrind complaints regarding glib aquiring
+ * locks internally. so fix bug a or bug b. let's leave the original
+ * bug in then and leave this as a note for now
+ */
+ /*
+ * It should be fine now as we do wait for thread to shutdown before
+ * we try to destroy the pipe.
+ */
+ p = _thread_call;
+ _thread_call = NULL;
+ _ecore_pipe_wait(p, 1, 0.1);
+ _ecore_pipe_del(p);
+ eina_lock_free(&_thread_safety);
+ eina_condition_free(&_thread_cond);
+ eina_lock_free(&_thread_mutex);
+ eina_condition_free(&_thread_feedback_cond);
+ eina_lock_free(&_thread_feedback_mutex);
+ eina_lock_free(&_thread_id_lock);
+
+
+#ifndef HAVE_EXOTIC
+ _ecore_exe_shutdown();
+#endif
+ _ecore_idle_enterer_shutdown();
+ _ecore_idle_exiter_shutdown();
+ _ecore_idler_shutdown();
+ _ecore_timer_shutdown();
+ _ecore_event_shutdown();
+ _ecore_main_shutdown();
+ _ecore_signal_shutdown();
+ _ecore_main_loop_shutdown();
+
+#if HAVE_MALLINFO
+ if (getenv("ECORE_MEM_STAT"))
+ {
+ _ecore_memory_statistic(NULL);
+
+ ERR("[%i] Memory MAX total: %i, free: %i",
+ _ecore_memory_pid,
+ _ecore_memory_max_total,
+ _ecore_memory_max_free);
+ }
+#endif
+ ecore_mempool_shutdown();
+ eina_log_domain_unregister(_ecore_log_dom);
+ _ecore_log_dom = -1;
+ eina_shutdown();
+#ifdef HAVE_EVIL
+ evil_shutdown();
+#endif
+
+ eo_unref(_ecore_parent);
+ eo_shutdown();
+unlock:
+ _ecore_unlock();
+
+ return _ecore_init_count;
+}
+
+struct _Ecore_Fork_Cb
+{
+ Ecore_Cb func;
+ void *data;
+ Eina_Bool delete_me : 1;
+};
+
+typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb;
+
+static int fork_cbs_walking = 0;
+static Eina_List *fork_cbs = NULL;
+
+EAPI Eina_Bool
+ecore_fork_reset_callback_add(Ecore_Cb func, const void *data)
+{
+ Ecore_Fork_Cb *fcb;
+
+ fcb = calloc(1, sizeof(Ecore_Fork_Cb));
+ if (!fcb) return EINA_FALSE;
+ fcb->func = func;
+ fcb->data = (void *)data;
+ fork_cbs = eina_list_append(fork_cbs, fcb);
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_fork_reset_callback_del(Ecore_Cb func, const void *data)
+{
+ Eina_List *l;
+ Ecore_Fork_Cb *fcb;
+
+ EINA_LIST_FOREACH(fork_cbs, l, fcb)
+ {
+ if ((fcb->func == func) && (fcb->data == data))
+ {
+ if (!fork_cbs_walking)
+ {
+ fork_cbs = eina_list_remove_list(fork_cbs, l);
+ free(fcb);
+ }
+ else
+ fcb->delete_me = EINA_TRUE;
+ return EINA_TRUE;
+ }
+ }
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_fork_reset(void)
+{
+ Eina_List *l, *ln;
+ Ecore_Fork_Cb *fcb;
+
+ eina_lock_take(&_thread_safety);
+
+ ecore_pipe_del(_thread_call);
+ _thread_call = ecore_pipe_add(_thread_callback, NULL);
+ /* If there was something in the pipe, trigger a wakeup again */
+ if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
+
+ eina_lock_release(&_thread_safety);
+
+ // should this be done withing the eina lock stuff?
+
+ fork_cbs_walking++;
+ EINA_LIST_FOREACH(fork_cbs, l, fcb)
+ {
+ fcb->func(fcb->data);
+ }
+ fork_cbs_walking--;
+
+ EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb)
+ {
+ if (fcb->delete_me)
+ {
+ fork_cbs = eina_list_remove_list(fork_cbs, l);
+ free(fcb);
+ }
+ }
+}
+
+/**
+ * @}
+ */
+
+EAPI void
+ecore_main_loop_thread_safe_call_async(Ecore_Cb callback,
+ void *data)
+{
+ Ecore_Safe_Call *order;
+
+ if (!callback) return;
+
+ if (eina_main_loop_is())
+ {
+ callback(data);
+ return;
+ }
+
+ order = malloc(sizeof (Ecore_Safe_Call));
+ if (!order) return;
+
+ order->cb.async = callback;
+ order->data = data;
+ order->sync = EINA_FALSE;
+ order->suspend = EINA_FALSE;
+
+ _ecore_main_loop_thread_safe_call(order);
+}
+
+EAPI void *
+ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,
+ void *data)
+{
+ Ecore_Safe_Call *order;
+ void *ret;
+
+ if (!callback) return NULL;
+
+ if (eina_main_loop_is())
+ {
+ return callback(data);
+ }
+
+ order = malloc(sizeof (Ecore_Safe_Call));
+ if (!order) return NULL;
+
+ order->cb.sync = callback;
+ order->data = data;
+ eina_lock_new(&order->m);
+ eina_condition_new(&order->c, &order->m);
+ order->sync = EINA_TRUE;
+ order->suspend = EINA_FALSE;
+
+ _ecore_main_loop_thread_safe_call(order);
+
+ eina_lock_take(&order->m);
+ eina_condition_wait(&order->c);
+ eina_lock_release(&order->m);
+
+ ret = order->data;
+
+ order->sync = EINA_FALSE;
+ order->cb.async = _thread_safe_cleanup;
+ order->data = order;
+
+ _ecore_main_loop_thread_safe_call(order);
+
+ return ret;
+}
+
+EAPI int
+ecore_thread_main_loop_begin(void)
+{
+ Ecore_Safe_Call *order;
+
+ if (eina_main_loop_is())
+ {
+ return ++_thread_loop;
+ }
+
+ order = malloc(sizeof (Ecore_Safe_Call));
+ if (!order) return -1;
+
+ eina_lock_take(&_thread_id_lock);
+ order->current_id = ++_thread_id_max;
+ if (order->current_id < 0)
+ {
+ _thread_id_max = 0;
+ order->current_id = ++_thread_id_max;
+ }
+ eina_lock_release(&_thread_id_lock);
+
+ eina_lock_new(&order->m);
+ eina_condition_new(&order->c, &order->m);
+ order->suspend = EINA_TRUE;
+
+ _ecore_main_loop_thread_safe_call(order);
+
+ eina_lock_take(&order->m);
+ while (order->current_id != _thread_id)
+ eina_condition_wait(&order->c);
+ eina_lock_release(&order->m);
+
+ eina_main_loop_define();
+
+ _thread_loop = 1;
+
+ return EINA_TRUE;
+}
+
+EAPI int
+ecore_thread_main_loop_end(void)
+{
+ int current_id;
+
+ if (_thread_loop == 0)
+ {
+ ERR("the main loop is not locked ! No matching call to ecore_thread_main_loop_begin().");
+ return -1;
+ }
+
+ /* until we unlock the main loop, this thread has the main loop id */
+ if (!eina_main_loop_is())
+ {
+ ERR("Not in a locked thread !");
+ return -1;
+ }
+
+ _thread_loop--;
+ if (_thread_loop > 0)
+ return _thread_loop;
+
+ current_id = _thread_id;
+
+ eina_lock_take(&_thread_mutex);
+ _thread_id_update = _thread_id;
+ eina_condition_broadcast(&_thread_cond);
+ eina_lock_release(&_thread_mutex);
+
+ eina_lock_take(&_thread_feedback_mutex);
+ while (current_id == _thread_id && _thread_id != -1)
+ eina_condition_wait(&_thread_feedback_cond);
+ eina_lock_release(&_thread_feedback_mutex);
+
+ return 0;
+}
+
+EAPI void
+ecore_print_warning(const char *function EINA_UNUSED,
+ const char *sparam EINA_UNUSED)
+{
+ WRN("***** Developer Warning ***** :\n"
+ "\tThis program is calling:\n\n"
+ "\t%s();\n\n"
+ "\tWith the parameter:\n\n"
+ "\t%s\n\n"
+ "\tbeing NULL. Please fix your program.", function, sparam);
+ if (getenv("ECORE_ERROR_ABORT")) abort();
+}
+
+EAPI void
+_ecore_magic_fail(const void *d,
+ Ecore_Magic m,
+ Ecore_Magic req_m,
+ const char *fname EINA_UNUSED)
+{
+ ERR("\n"
+ "*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
+ "*** IN FUNCTION: %s()", fname);
+ if (!d)
+ ERR(" Input handle pointer is NULL!");
+ else if (m == ECORE_MAGIC_NONE)
+ ERR(" Input handle has already been freed!");
+ else if (m != req_m)
+ ERR(" Input handle is wrong type\n"
+ " Expected: %08x - %s\n"
+ " Supplied: %08x - %s",
+ (unsigned int)req_m, _ecore_magic_string_get(req_m),
+ (unsigned int)m, _ecore_magic_string_get(m));
+ ERR("*** NAUGHTY PROGRAMMER!!!\n"
+ "*** SPANK SPANK SPANK!!!\n"
+ "*** Now go fix your code. Tut tut tut!");
+ if (getenv("ECORE_ERROR_ABORT")) abort();
+}
+
+static const char *
+_ecore_magic_string_get(Ecore_Magic m)
+{
+ switch (m)
+ {
+ case ECORE_MAGIC_NONE:
+ return "None (Freed Object)";
+ break;
+
+ case ECORE_MAGIC_EXE:
+ return "Ecore_Exe (Executable)";
+ break;
+
+ case ECORE_MAGIC_TIMER:
+ return "Ecore_Timer (Timer)";
+ break;
+
+ case ECORE_MAGIC_IDLER:
+ return "Ecore_Idler (Idler)";
+ break;
+
+ case ECORE_MAGIC_IDLE_ENTERER:
+ return "Ecore_Idle_Enterer (Idler Enterer)";
+ break;
+
+ case ECORE_MAGIC_IDLE_EXITER:
+ return "Ecore_Idle_Exiter (Idler Exiter)";
+ break;
+
+ case ECORE_MAGIC_FD_HANDLER:
+ return "Ecore_Fd_Handler (Fd Handler)";
+ break;
+
+ case ECORE_MAGIC_WIN32_HANDLER:
+ return "Ecore_Win32_Handler (Win32 Handler)";
+ break;
+
+ case ECORE_MAGIC_EVENT_HANDLER:
+ return "Ecore_Event_Handler (Event Handler)";
+ break;
+
+ case ECORE_MAGIC_EVENT:
+ return "Ecore_Event (Event)";
+ break;
+
+ default:
+ return "<UNKNOWN>";
+ }
+}
+
+/* fps debug calls - for debugging how much time your app actually spends */
+/* "running" (and the inverse being time spent running)... this does not */
+/* account for other apps and multitasking... */
+
+static int _ecore_fps_debug_init_count = 0;
+static int _ecore_fps_debug_fd = -1;
+unsigned int *_ecore_fps_runtime_mmap = NULL;
+
+void
+_ecore_fps_debug_init(void)
+{
+ char buf[PATH_MAX];
+ const char *tmp;
+ int pid;
+
+ _ecore_fps_debug_init_count++;
+ if (_ecore_fps_debug_init_count > 1) return;
+
+#ifndef HAVE_EVIL
+ tmp = "/tmp";
+#else
+ tmp = evil_tmpdir_get ();
+#endif /* HAVE_EVIL */
+ pid = (int)getpid();
+ snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
+ _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (_ecore_fps_debug_fd < 0)
+ {
+ unlink(buf);
+ _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ }
+ if (_ecore_fps_debug_fd >= 0)
+ {
+ unsigned int zero = 0;
+ char *buf2 = (char *)&zero;
+ ssize_t todo = sizeof(unsigned int);
+
+ while (todo > 0)
+ {
+ ssize_t r = write(_ecore_fps_debug_fd, buf2, todo);
+ if (r > 0)
+ {
+ todo -= r;
+ buf2 += r;
+ }
+ else if ((r < 0) && (errno == EINTR))
+ continue;
+ else
+ {
+ ERR("could not write to file '%s' fd %d: %s",
+ tmp, _ecore_fps_debug_fd, strerror(errno));
+ close(_ecore_fps_debug_fd);
+ _ecore_fps_debug_fd = -1;
+ return;
+ }
+ }
+ _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ _ecore_fps_debug_fd, 0);
+ if (_ecore_fps_runtime_mmap == MAP_FAILED)
+ _ecore_fps_runtime_mmap = NULL;
+ }
+}
+
+void
+_ecore_fps_debug_shutdown(void)
+{
+ _ecore_fps_debug_init_count--;
+ if (_ecore_fps_debug_init_count > 0) return;
+ if (_ecore_fps_debug_fd >= 0)
+ {
+ char buf[4096];
+ const char *tmp;
+ int pid;
+
+#ifndef HAVE_EVIL
+ tmp = "/tmp";
+#else
+ tmp = (char *)evil_tmpdir_get ();
+#endif /* HAVE_EVIL */
+ pid = (int)getpid();
+ snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
+ unlink(buf);
+ if (_ecore_fps_runtime_mmap)
+ {
+ munmap(_ecore_fps_runtime_mmap, sizeof(int));
+ _ecore_fps_runtime_mmap = NULL;
+ }
+ close(_ecore_fps_debug_fd);
+ _ecore_fps_debug_fd = -1;
+ }
+}
+
+void
+_ecore_fps_debug_runtime_add(double t)
+{
+ if ((_ecore_fps_debug_fd >= 0) &&
+ (_ecore_fps_runtime_mmap))
+ {
+ unsigned int tm;
+
+ tm = (unsigned int)(t * 1000000.0);
+ /* i know its not 100% theoretically guaranteed, but i'd say a write */
+ /* of an int could be considered atomic for all practical purposes */
+ /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
+ /* this can run for about 4294 seconds becore looping. if you are */
+ /* doing performance testing in one run for over an hour... well */
+ /* time to restart or handle a loop condition :) */
+ *(_ecore_fps_runtime_mmap) += tm;
+ }
+}
+
+#if HAVE_MALLINFO
+static Eina_Bool
+_ecore_memory_statistic(EINA_UNUSED void *data)
+{
+ struct mallinfo mi;
+ static int uordblks = 0;
+ static int fordblks = 0;
+ Eina_Bool changed = EINA_FALSE;
+
+ mi = mallinfo();
+
+#define HAS_CHANGED(Global, Local) \
+ if (Global != Local) \
+ { \
+ Global = Local; \
+ changed = EINA_TRUE; \
+ }
+
+ HAS_CHANGED(uordblks, mi.uordblks);
+ HAS_CHANGED(fordblks, mi.fordblks);
+
+ if (changed)
+ ERR("[%i] Memory total: %i, free: %i",
+ _ecore_memory_pid,
+ mi.uordblks,
+ mi.fordblks);
+
+ KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
+ KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+#endif
+
+static void
+_ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
+{
+ Eina_Bool count;
+
+ eina_lock_take(&_thread_safety);
+
+ count = _thread_cb ? 0 : 1;
+ _thread_cb = eina_list_append(_thread_cb, order);
+ if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
+
+ eina_lock_release(&_thread_safety);
+}
+
+static void
+_thread_safe_cleanup(void *data)
+{
+ Ecore_Safe_Call *call = data;
+
+ eina_condition_free(&call->c);
+ eina_lock_free(&call->m);
+}
+
+void
+_ecore_main_call_flush(void)
+{
+ Ecore_Safe_Call *call;
+ Eina_List *callback;
+
+ eina_lock_take(&_thread_safety);
+ callback = _thread_cb;
+ _thread_cb = NULL;
+ eina_lock_release(&_thread_safety);
+
+ EINA_LIST_FREE(callback, call)
+ {
+ if (call->suspend)
+ {
+ eina_lock_take(&_thread_mutex);
+
+ eina_lock_take(&call->m);
+ _thread_id = call->current_id;
+ eina_condition_broadcast(&call->c);
+ eina_lock_release(&call->m);
+
+ while (_thread_id_update != _thread_id)
+ eina_condition_wait(&_thread_cond);
+ eina_lock_release(&_thread_mutex);
+
+ eina_main_loop_define();
+
+ eina_lock_take(&_thread_feedback_mutex);
+
+ _thread_id = -1;
+
+ eina_condition_broadcast(&_thread_feedback_cond);
+ eina_lock_release(&_thread_feedback_mutex);
+
+ _thread_safe_cleanup(call);
+ free(call);
+ }
+ else if (call->sync)
+ {
+ call->data = call->cb.sync(call->data);
+ eina_condition_broadcast(&call->c);
+ }
+ else
+ {
+ call->cb.async(call->data);
+ free(call);
+ }
+ }
+}
+
+static void
+_thread_callback(void *data EINA_UNUSED,
+ void *buffer EINA_UNUSED,
+ unsigned int nbyte EINA_UNUSED)
+{
+ _ecore_main_call_flush();
+}
+
+static const Eo_Class_Description parent_class_desc = {
+ EO_VERSION,
+ "ecore_parent",
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
+ NULL,
+ 0,
+ NULL,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_parent_class_get, &parent_class_desc, EO_BASE_CLASS, NULL);
diff --git a/src/lib/ecore/ecore_alloc.c b/src/lib/ecore/ecore_alloc.c
new file mode 100644
index 0000000000..bec66ef0d5
--- /dev/null
+++ b/src/lib/ecore/ecore_alloc.c
@@ -0,0 +1,132 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <Eina.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+typedef struct _Ecore_Mempool Ecore_Mempool;
+struct _Ecore_Mempool
+{
+ const char *name;
+ Eina_Mempool *mp;
+ size_t size;
+};
+
+#define GENERIC_ALLOC_FREE(TYPE, Type) \
+ extern size_t _ecore_sizeof_##TYPE; \
+ Ecore_Mempool Type##_mp = { #TYPE, NULL, 0 }; \
+ TYPE * \
+ Type##_calloc(unsigned int num) \
+ { \
+ return eina_mempool_calloc(Type##_mp.mp, \
+ num * _ecore_sizeof_##TYPE); \
+ } \
+ void \
+ Type##_mp_free(TYPE *e) \
+ { \
+ eina_mempool_free(Type##_mp.mp, e); \
+ }
+
+//GENERIC_ALLOC_FREE(Ecore_Animator, ecore_animator);
+GENERIC_ALLOC_FREE(Ecore_Event_Handler, ecore_event_handler);
+GENERIC_ALLOC_FREE(Ecore_Event_Filter, ecore_event_filter);
+GENERIC_ALLOC_FREE(Ecore_Event, ecore_event);
+//GENERIC_ALLOC_FREE(Ecore_Idle_Exiter, ecore_idle_exiter);
+//GENERIC_ALLOC_FREE(Ecore_Idle_Enterer, ecore_idle_enterer);
+//GENERIC_ALLOC_FREE(Ecore_Idler, ecore_idler);
+//GENERIC_ALLOC_FREE(Ecore_Job, ecore_job);
+//GENERIC_ALLOC_FREE(Ecore_Timer, ecore_timer);
+//GENERIC_ALLOC_FREE(Ecore_Poller, ecore_poller);
+GENERIC_ALLOC_FREE(Ecore_Pipe, ecore_pipe);
+GENERIC_ALLOC_FREE(Ecore_Fd_Handler, ecore_fd_handler);
+#ifdef _WIN32
+GENERIC_ALLOC_FREE(Ecore_Win32_Handler, ecore_win32_handler);
+#endif
+
+static Ecore_Mempool *mempool_array[] = {
+// &ecore_animator_mp,
+ &ecore_event_handler_mp,
+ &ecore_event_filter_mp,
+ &ecore_event_mp,
+// &ecore_idle_exiter_mp,
+// &ecore_idle_enterer_mp,
+// &ecore_idler_mp,
+// &ecore_job_mp,
+// &ecore_timer_mp,
+// &ecore_poller_mp,
+ &ecore_pipe_mp,
+ &ecore_fd_handler_mp,
+#ifdef _WIN32
+ &ecore_win32_handler_mp
+#endif
+};
+
+Eina_Bool
+ecore_mempool_init(void)
+{
+ const char *choice;
+ unsigned int i;
+
+#define MP_SIZE_INIT(TYPE, Type) \
+ Type##_mp.size = _ecore_sizeof_##TYPE
+
+// MP_SIZE_INIT(Ecore_Animator, ecore_animator);
+ MP_SIZE_INIT(Ecore_Event_Handler, ecore_event_handler);
+ MP_SIZE_INIT(Ecore_Event_Filter, ecore_event_filter);
+ MP_SIZE_INIT(Ecore_Event, ecore_event);
+// MP_SIZE_INIT(Ecore_Idle_Exiter, ecore_idle_exiter);
+// MP_SIZE_INIT(Ecore_Idle_Enterer, ecore_idle_enterer);
+// MP_SIZE_INIT(Ecore_Idler, ecore_idler);
+// MP_SIZE_INIT(Ecore_Job, ecore_job);
+// MP_SIZE_INIT(Ecore_Timer, ecore_timer);
+// MP_SIZE_INIT(Ecore_Poller, ecore_poller);
+ MP_SIZE_INIT(Ecore_Pipe, ecore_pipe);
+ MP_SIZE_INIT(Ecore_Fd_Handler, ecore_fd_handler);
+#ifdef _WIN32
+ MP_SIZE_INIT(Ecore_Win32_Handler, ecore_win32_handler);
+#endif
+#undef MP_SIZE_INIT
+
+ choice = getenv("EINA_MEMPOOL");
+ if ((!choice) || (!choice[0]))
+ choice = "chained_mempool";
+
+ for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i)
+ {
+ retry:
+ mempool_array[i]->mp = eina_mempool_add(choice, mempool_array[i]->name, NULL, mempool_array[i]->size, 16);
+ if (!mempool_array[i]->mp)
+ {
+ if (!(!strcmp(choice, "pass_through")))
+ {
+ ERR("Falling back to pass through ! Previously tried '%s' mempool.", choice);
+ choice = "pass_through";
+ goto retry;
+ }
+ else
+ {
+ ERR("Impossible to allocate mempool '%s' !", choice);
+ return EINA_FALSE;
+ }
+ }
+ }
+ return EINA_TRUE;
+}
+
+void
+ecore_mempool_shutdown(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i)
+ {
+ eina_mempool_del(mempool_array[i]->mp);
+ mempool_array[i]->mp = NULL;
+ }
+}
+
diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c
new file mode 100644
index 0000000000..c06d139add
--- /dev/null
+++ b/src/lib/ecore/ecore_anim.c
@@ -0,0 +1,633 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_ANIMATOR_CLASS
+
+#define MY_CLASS_NAME "ecore_animator"
+
+#define ECORE_ANIMATOR_CHECK(obj) \
+ if (!eo_isa((obj), ECORE_ANIMATOR_CLASS)) \
+ return
+
+EAPI Eo_Op ECORE_ANIMATOR_BASE_ID = EO_NOOP;
+
+struct _Ecore_Animator_Private_Data
+{
+ EINA_INLIST;
+ Ecore_Animator *obj;
+
+ Ecore_Task_Cb func;
+ void *data;
+
+ double start, run;
+ Ecore_Timeline_Cb run_func;
+ void *run_data;
+
+ Eina_Bool delete_me : 1;
+ Eina_Bool suspended : 1;
+ Eina_Bool just_added : 1;
+};
+
+typedef struct _Ecore_Animator_Private_Data Ecore_Animator_Private_Data;
+
+static Eina_Bool _ecore_animator_run(void *data);
+static Eina_Bool _ecore_animator(void *data);
+
+static int animators_delete_me = 0;
+static Ecore_Animator_Private_Data *animators = NULL;
+static double animators_frametime = 1.0 / 30.0;
+
+static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
+static Ecore_Timer *timer = NULL;
+static int ticking = 0;
+static Ecore_Cb begin_tick_cb = NULL;
+static const void *begin_tick_data = NULL;
+static Ecore_Cb end_tick_cb = NULL;
+static const void *end_tick_data = NULL;
+
+static void
+_begin_tick(void)
+{
+ if (ticking) return;
+ ticking = 1;
+ switch (src)
+ {
+ case ECORE_ANIMATOR_SOURCE_TIMER:
+ if (!timer)
+ {
+ double t_loop = ecore_loop_time_get();
+ double sync_0 = 0.0;
+ double d = -fmod(t_loop - sync_0, animators_frametime);
+
+ timer = _ecore_timer_loop_add(animators_frametime,
+ _ecore_animator, NULL);
+ _ecore_timer_delay(timer, d);
+ }
+ break;
+
+ case ECORE_ANIMATOR_SOURCE_CUSTOM:
+ if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+_end_tick(void)
+{
+ if (!ticking) return;
+ ticking = 0;
+ switch (src)
+ {
+ case ECORE_ANIMATOR_SOURCE_TIMER:
+ if (timer)
+ {
+ _ecore_timer_del(timer);
+ timer = NULL;
+ }
+ break;
+
+ case ECORE_ANIMATOR_SOURCE_CUSTOM:
+ if (end_tick_cb) end_tick_cb((void *)end_tick_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static Eina_Bool
+_do_tick(void)
+{
+ Ecore_Animator_Private_Data *animator;
+
+ EINA_INLIST_FOREACH(animators, animator)
+ {
+ animator->just_added = EINA_FALSE;
+ }
+ EINA_INLIST_FOREACH(animators, animator)
+ {
+ if ((!animator->delete_me) &&
+ (!animator->suspended) &&
+ (!animator->just_added))
+ {
+ if (!_ecore_call_task_cb(animator->func, animator->data))
+ {
+ animator->delete_me = EINA_TRUE;
+ animators_delete_me++;
+ }
+ }
+ else animator->just_added = EINA_FALSE;
+ }
+ if (animators_delete_me)
+ {
+ Ecore_Animator_Private_Data *l;
+ for (l = animators; l; )
+ {
+ animator = l;
+ l = (Ecore_Animator_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (animator->delete_me)
+ {
+ animators = (Ecore_Animator_Private_Data *)
+ eina_inlist_remove(EINA_INLIST_GET(animators),
+ EINA_INLIST_GET(animator));
+
+ eo_parent_set(animator->obj, NULL);
+ if (eo_destructed_is(animator->obj))
+ eo_manual_free(animator->obj);
+ else
+ eo_manual_free_set(animator->obj, EINA_FALSE);
+
+ animators_delete_me--;
+ if (animators_delete_me == 0) break;
+ }
+ }
+ }
+ if (!animators)
+ {
+ _end_tick();
+ return ECORE_CALLBACK_CANCEL;
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_animator_add(Ecore_Animator *obj,
+ Ecore_Animator_Private_Data *animator,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
+ }
+
+ animator->obj = obj;
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return EINA_FALSE;
+ }
+
+ animator->func = func;
+ animator->data = (void *)data;
+ animator->just_added = EINA_TRUE;
+ animators = (Ecore_Animator_Private_Data *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
+ _begin_tick();
+ return EINA_TRUE;
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+EAPI Ecore_Animator *
+ecore_animator_add(Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Animator *animator = NULL;
+
+ animator = eo_add_custom(MY_CLASS, _ecore_parent,
+ ecore_animator_constructor(func, data));
+ eo_unref(animator);
+ return animator;
+}
+
+static void
+_animator_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ _ecore_lock();
+ Ecore_Animator_Private_Data *animator = _pd;
+ _ecore_animator_add(obj, animator, func, data);
+ _ecore_unlock();
+}
+
+EAPI Ecore_Animator *
+ecore_animator_timeline_add(double runtime,
+ Ecore_Timeline_Cb func,
+ const void *data)
+{
+ Ecore_Animator *animator;
+ animator = eo_add_custom(MY_CLASS, _ecore_parent,
+ ecore_animator_timeline_constructor(runtime, func, data));
+ eo_unref(animator);
+ return animator;
+}
+
+static void
+_animator_timeline_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ _ecore_lock();
+ double runtime = va_arg(*list, double);
+ if (runtime <= 0.0) runtime = 0.0;
+ Ecore_Timeline_Cb func = va_arg(*list, Ecore_Timeline_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ Ecore_Animator_Private_Data *animator = _pd;
+ if (!_ecore_animator_add(obj, animator, _ecore_animator_run, NULL)) goto unlock;
+
+ animator->data = obj;
+ animator->run_func = func;
+ animator->run_data = (void *)data;
+ animator->start = ecore_loop_time_get();
+ animator->run = runtime;
+
+unlock:
+ _ecore_unlock();
+}
+
+static double
+_pos_map_sin(double in)
+{
+ return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in)));
+}
+
+#if 0
+static double
+_pos_map_cos(double in)
+{
+ return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in)));
+}
+#endif
+
+static double
+_pos_map_accel_factor(double pos,
+ double v1)
+{
+ int i, fact = (int)v1;
+ double p, o1 = pos, o2, v;
+ p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0));
+ o2 = p;
+ for (i = 0; i < fact; i++)
+ {
+ o1 = o2;
+ o2 = o2 * p;
+ }
+ v = v1 - (double)fact;
+ pos = (v * o2) + ((1.0 - v) * o1);
+ return pos;
+}
+
+static double
+_pos_map_pow(double pos,
+ double divis,
+ int p)
+{
+ double v = 1.0;
+ int i;
+ for (i = 0; i < p; i++) v *= pos;
+ return ((pos * divis) * (1.0 - v)) + (pos * v);
+}
+
+static double
+_pos_map_spring(double pos,
+ int bounces,
+ double decfac)
+{
+ int segnum, segpos, b1, b2;
+ double len, decay, decpos, p2;
+ if (bounces < 0) bounces = 0;
+ p2 = _pos_map_pow(pos, 0.5, 3);
+ len = (M_PI / 2.0) + ((double)bounces * M_PI);
+ segnum = (bounces * 2) + 1;
+ segpos = 2 * (((int)(p2 * segnum) + 1) / 2);
+ b1 = segpos;
+ b2 = segnum + 1;
+ if (b1 < 0) b1 = 0;
+ decpos = (double)b1 / (double)b2;
+ decay = _pos_map_accel_factor(1.0 - decpos, decfac);
+ return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay;
+}
+
+#define DBL_TO(Fp) eina_f32p32_double_to(Fp)
+#define DBL_FROM(D) eina_f32p32_double_from(D)
+#define INT_FROM(I) eina_f32p32_int_from(I)
+#define SIN(Fp) eina_f32p32_sin(Fp)
+#define COS(Fp) eina_f32p32_cos(Fp)
+#define ADD(A, B) eina_f32p32_add(A, B)
+#define SUB(A, B) eina_f32p32_sub(A, B)
+#define MUL(A, B) eina_f32p32_mul(A, B)
+
+EAPI double
+ecore_animator_pos_map(double pos,
+ Ecore_Pos_Map map,
+ double v1,
+ double v2)
+{
+ /* purely functional - locking not required */
+ if (pos > 1.0) pos = 1.0;
+ else if (pos < 0.0)
+ pos = 0.0;
+ switch (map)
+ {
+ case ECORE_POS_MAP_LINEAR:
+ return pos;
+
+ case ECORE_POS_MAP_ACCELERATE:
+ /* pos = 1 - sin(Pi / 2 + pos * Pi / 2); */
+ pos = DBL_TO(SUB(INT_FROM(1), SIN(ADD((EINA_F32P32_PI >> 1), MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))))));
+ return pos;
+
+ case ECORE_POS_MAP_DECELERATE:
+ /* pos = sin(pos * Pi / 2); */
+ pos = DBL_TO(SIN(MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))));
+ return pos;
+
+ case ECORE_POS_MAP_SINUSOIDAL:
+ /* pos = (1 - cos(pos * Pi)) / 2 */
+ pos = DBL_TO((SUB(INT_FROM(1), COS(MUL(DBL_FROM(pos), EINA_F32P32_PI)))) >> 1);
+ return pos;
+
+ case ECORE_POS_MAP_ACCELERATE_FACTOR:
+ pos = _pos_map_accel_factor(pos, v1);
+ return pos;
+
+ case ECORE_POS_MAP_DECELERATE_FACTOR:
+ pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v1);
+ return pos;
+
+ case ECORE_POS_MAP_SINUSOIDAL_FACTOR:
+ if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v1) / 2.0;
+ else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v1) / 2.0);
+ return pos;
+
+ case ECORE_POS_MAP_DIVISOR_INTERP:
+ pos = _pos_map_pow(pos, v1, (int)v2);
+ return pos;
+
+ case ECORE_POS_MAP_BOUNCE:
+ pos = _pos_map_spring(pos, (int)v2, v1);
+ if (pos < 0.0) pos = -pos;
+ pos = 1.0 - pos;
+ return pos;
+
+ case ECORE_POS_MAP_SPRING:
+ pos = 1.0 - _pos_map_spring(pos, (int)v2, v1);
+ return pos;
+
+ default:
+ return pos;
+ }
+ return pos;
+}
+
+EAPI void *
+ecore_animator_del(Ecore_Animator *obj)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ Ecore_Animator_Private_Data *animator = eo_data_get(obj, MY_CLASS);
+ _ecore_lock();
+
+ if (animator->delete_me)
+ {
+ data = animator->data;
+ goto unlock;
+ }
+ animator->delete_me = EINA_TRUE;
+ animators_delete_me++;
+ if (animator->run_func)
+ data = animator->run_data;
+ else
+ data = animator->data;
+unlock:
+ _ecore_unlock();
+ return data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Animator_Private_Data *pd = _pd;
+
+ pd->delete_me = EINA_TRUE;
+ animators_delete_me++;
+
+ eo_do_super(obj, eo_destructor());
+}
+
+EAPI void
+ecore_animator_frametime_set(double frametime)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ if (frametime < 0.0) frametime = 0.0;
+ if (animators_frametime == frametime) goto unlock;
+ animators_frametime = frametime;
+ _end_tick();
+ if (animators) _begin_tick();
+unlock:
+ _ecore_unlock();
+}
+
+EAPI double
+ecore_animator_frametime_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
+ return animators_frametime;
+}
+
+EAPI void
+ecore_animator_freeze(Ecore_Animator *animator)
+{
+ ECORE_ANIMATOR_CHECK(animator);
+ eo_do(animator, eo_event_freeze());
+}
+
+static void
+_ecore_animator_freeze(Eo *obj EINA_UNUSED, void *_pd,
+ va_list *list EINA_UNUSED)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ Ecore_Animator_Private_Data *animator = _pd;
+
+ if (animator->delete_me) goto unlock;
+ animator->suspended = EINA_TRUE;
+unlock:
+ _ecore_unlock();
+}
+
+EAPI void
+ecore_animator_thaw(Ecore_Animator *animator)
+{
+ ECORE_ANIMATOR_CHECK(animator);
+ eo_do(animator, eo_event_thaw());
+}
+
+static void
+_ecore_animator_thaw(Eo *obj EINA_UNUSED, void *_pd,
+ va_list *list EINA_UNUSED)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ Ecore_Animator_Private_Data *animator = _pd;
+
+ _ecore_lock();
+ if (animator->delete_me) goto unlock;
+ animator->suspended = EINA_FALSE;
+unlock:
+ _ecore_unlock();
+}
+
+EAPI void
+ecore_animator_source_set(Ecore_Animator_Source source)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ src = source;
+ _end_tick();
+ if (animators) _begin_tick();
+ _ecore_unlock();
+}
+
+EAPI Ecore_Animator_Source
+ecore_animator_source_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ return src;
+}
+
+EAPI void
+ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func,
+ const void *data)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ begin_tick_cb = func;
+ begin_tick_data = data;
+ _end_tick();
+ if (animators) _begin_tick();
+ _ecore_unlock();
+}
+
+EAPI void
+ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func,
+ const void *data)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ end_tick_cb = func;
+ end_tick_data = data;
+ _end_tick();
+ if (animators) _begin_tick();
+ _ecore_unlock();
+}
+
+EAPI void
+ecore_animator_custom_tick(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ if (src == ECORE_ANIMATOR_SOURCE_CUSTOM) _do_tick();
+ _ecore_unlock();
+}
+
+void
+_ecore_animator_shutdown(void)
+{
+ _end_tick();
+ while (animators)
+ {
+ Ecore_Animator_Private_Data *animator;
+
+ animator = animators;
+ animators = (Ecore_Animator_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators));
+
+ eo_parent_set(animator->obj, NULL);
+ if (eo_destructed_is(animator->obj))
+ eo_manual_free(animator->obj);
+ else
+ eo_manual_free_set(animator->obj, EINA_FALSE);
+ }
+}
+
+static Eina_Bool
+_ecore_animator_run(void *data)
+{
+ Ecore_Animator *obj = data;
+ Ecore_Animator_Private_Data *animator = eo_data_get(obj, MY_CLASS);
+
+ double pos = 0.0, t;
+ Eina_Bool run_ret;
+
+ t = ecore_loop_time_get();
+ if (animator->run > 0.0)
+ {
+ pos = (t - animator->start) / animator->run;
+ if (pos > 1.0) pos = 1.0;
+ else if (pos < 0.0)
+ pos = 0.0;
+ }
+ run_ret = animator->run_func(animator->run_data, pos);
+ if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE;
+ return run_ret;
+}
+
+static Eina_Bool
+_ecore_animator(void *data EINA_UNUSED)
+{
+ Eina_Bool r;
+ _ecore_lock();
+ r = _do_tick();
+ _ecore_unlock();
+ return r;
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_FREEZE), _ecore_animator_freeze),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_THAW), _ecore_animator_thaw),
+
+ EO_OP_FUNC(ECORE_ANIMATOR_ID(ECORE_ANIMATOR_SUB_ID_CONSTRUCTOR), _animator_constructor),
+ EO_OP_FUNC(ECORE_ANIMATOR_ID(ECORE_ANIMATOR_SUB_ID_TIMELINE_CONSTRUCTOR), _animator_timeline_constructor),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_ANIMATOR_SUB_ID_CONSTRUCTOR, "Add an animator to call func at every animation tick during main loop execution."),
+ EO_OP_DESCRIPTION(ECORE_ANIMATOR_SUB_ID_TIMELINE_CONSTRUCTOR, "Add an animator that runs for a limited time"),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_ANIMATOR_BASE_ID, op_desc, ECORE_ANIMATOR_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Animator_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_animator_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore/ecore_app.c b/src/lib/ecore/ecore_app.c
new file mode 100644
index 0000000000..04df487d3c
--- /dev/null
+++ b/src/lib/ecore/ecore_app.c
@@ -0,0 +1,98 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef _MSC_VER
+# include <process.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static int app_argc = 0;
+static char **app_argv = NULL;
+
+/**
+ * @addtogroup Ecore_Application_Group
+ *
+ * @{
+ */
+
+/**
+ * Set up the programs command-line arguments.
+ * @param argc The same as passed as argc to the programs main() function
+ * @param argv The same as passed as argv to the programs main() function
+ *
+ * A call to this function will store the programs command-line arguments
+ * for later use by ecore_app_restart() or ecore_app_args_get().
+ */
+EAPI void
+ecore_app_args_set(int argc,
+ const char **argv)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ if ((argc < 1) ||
+ (!argv)) return;
+ app_argc = argc;
+ app_argv = (char **)argv;
+}
+
+/**
+ * Return the programs stored command-line arguments.
+ * @param argc A pointer to the return value to hold argc
+ * @param argv A pointer to the return value to hold argv
+ *
+ * When called, this funciton returns the arguments for the program stored by
+ * ecore_app_args_set(). The integer pointed to by @p argc will be filled, if
+ * the pointer is not NULL, and the string array pointer @p argv will be filled
+ * also if the pointer is not NULL. The values they are filled with will be the
+ * same set by ecore_app_args_set().
+ */
+EAPI void
+ecore_app_args_get(int *argc,
+ char ***argv)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ if (argc) *argc = app_argc;
+ if (argv) *argv = app_argv;
+}
+
+/**
+ * Restart the program executable with the command-line arguments stored.
+ *
+ * This function will restart & re-execute this program in place of itself
+ * using the command-line arguments stored by ecore_app_args_set(). This is
+ * an easy way for a program to restart itself for cleanup purposes,
+ * configuration reasons or in the event of a crash.
+ */
+EAPI void
+ecore_app_restart(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+#ifdef HAVE_EXECVP
+ char *args[4096];
+ int i;
+
+ if ((app_argc < 1) || (!app_argv)) return;
+ if (app_argc >= 4096) return;
+ for (i = 0; i < app_argc; i++) args[i] = app_argv[i];
+ args[i] = NULL;
+ execvp(app_argv[0], args);
+#endif
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore/ecore_events.c b/src/lib/ecore/ecore_events.c
new file mode 100644
index 0000000000..2d8ac1f661
--- /dev/null
+++ b/src/lib/ecore/ecore_events.c
@@ -0,0 +1,648 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static int inpurge = 0;
+
+struct _Ecore_Event_Handler
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ int type;
+ Ecore_Event_Handler_Cb func;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event_Handler);
+
+struct _Ecore_Event_Filter
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ Ecore_Data_Cb func_start;
+ Ecore_Filter_Cb func_filter;
+ Ecore_End_Cb func_end;
+ void *loop_data;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event_Filter);
+
+struct _Ecore_Event
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ int type;
+ void *event;
+ Ecore_End_Cb func_free;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event);
+
+static int events_num = 0;
+static Ecore_Event *events = NULL;
+static Ecore_Event *event_current = NULL;
+static Ecore_Event *purge_events = NULL;
+
+static Ecore_Event_Handler **event_handlers = NULL;
+static Ecore_Event_Handler *event_handler_current = NULL;
+static int event_handlers_num = 0;
+static int event_handlers_alloc_num = 0;
+static Eina_List *event_handlers_delete_list = NULL;
+
+static Ecore_Event_Handler *event_handlers_add_list = NULL;
+
+static Ecore_Event_Filter *event_filters = NULL;
+static Ecore_Event_Filter *event_filter_current = NULL;
+static Ecore_Event *event_filter_event_current = NULL;
+static int event_filters_delete_me = 0;
+static int event_id_max = ECORE_EVENT_COUNT;
+static int ecore_raw_event_type = ECORE_EVENT_NONE;
+static void *ecore_raw_event_event = NULL;
+
+static void _ecore_event_purge_deleted(void);
+static void *_ecore_event_del(Ecore_Event *event);
+
+EAPI Ecore_Event_Handler *
+ecore_event_handler_add(int type,
+ Ecore_Event_Handler_Cb func,
+ const void *data)
+{
+ Ecore_Event_Handler *eh = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+
+ if (!func) goto unlock;
+ if ((type <= ECORE_EVENT_NONE) || (type >= event_id_max)) goto unlock;
+ eh = ecore_event_handler_calloc(1);
+ if (!eh) goto unlock;
+ ECORE_MAGIC_SET(eh, ECORE_MAGIC_EVENT_HANDLER);
+ eh->type = type;
+ eh->func = func;
+ eh->data = (void *)data;
+ if (type >= (event_handlers_num - 1))
+ {
+ int p_alloc_num;
+
+ p_alloc_num = event_handlers_alloc_num;
+ event_handlers_num = type + 1;
+ if (event_handlers_num > event_handlers_alloc_num)
+ {
+ Ecore_Event_Handler **new_handlers;
+ int i;
+
+ event_handlers_alloc_num = ((event_handlers_num + 16) / 16) * 16;
+ new_handlers = realloc(event_handlers, event_handlers_alloc_num * sizeof(Ecore_Event_Handler *));
+ if (!new_handlers)
+ {
+ ecore_event_handler_mp_free(eh);
+ goto unlock;
+ }
+ event_handlers = new_handlers;
+ for (i = p_alloc_num; i < event_handlers_alloc_num; i++)
+ event_handlers[i] = NULL;
+ }
+ }
+ if (ecore_raw_event_type == type)
+ event_handlers_add_list = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers_add_list), EINA_INLIST_GET(eh));
+ else if (type < event_handlers_alloc_num)
+ event_handlers[type] = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers[type]), EINA_INLIST_GET(eh));
+
+unlock:
+ _ecore_unlock();
+ return eh;
+}
+
+EAPI void *
+ecore_event_handler_del(Ecore_Event_Handler *event_handler)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(event_handler, ECORE_MAGIC_EVENT_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(event_handler, ECORE_MAGIC_EVENT_HANDLER,
+ "ecore_event_handler_del");
+ goto unlock;
+ }
+ data = _ecore_event_handler_del(event_handler);
+unlock:
+ _ecore_unlock();
+
+ return data;
+}
+
+EAPI void *
+ecore_event_handler_data_get(Ecore_Event_Handler *eh)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(eh, ECORE_MAGIC_EVENT_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(eh, ECORE_MAGIC_EVENT_HANDLER, "ecore_event_handler_data_get");
+ goto unlock;
+ }
+ data = eh->data;
+unlock:
+ _ecore_unlock();
+ return data;
+}
+
+EAPI void *
+ecore_event_handler_data_set(Ecore_Event_Handler *eh,
+ const void *data)
+{
+ void *old = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(eh, ECORE_MAGIC_EVENT_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(eh, ECORE_MAGIC_EVENT_HANDLER, "ecore_event_handler_data_set");
+ goto unlock;
+ }
+ old = eh->data;
+ eh->data = (void *)data;
+unlock:
+ _ecore_unlock();
+
+ return old;
+}
+
+static void
+_ecore_event_generic_free(void *data EINA_UNUSED,
+ void *event)
+{ /* DO NOT MEMPOOL FREE THIS */
+ free(event);
+}
+
+EAPI Ecore_Event *
+ecore_event_add(int type,
+ void *ev,
+ Ecore_End_Cb func_free,
+ void *data)
+{
+ Ecore_Event *event = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+
+/* if (!ev) goto unlock; */
+ if (type <= ECORE_EVENT_NONE) goto unlock;
+ if (type >= event_id_max) goto unlock;
+ if ((ev) && (!func_free)) func_free = _ecore_event_generic_free;
+ event = _ecore_event_add(type, ev, func_free, data);
+unlock:
+ _ecore_unlock();
+ return event;
+}
+
+EAPI void *
+ecore_event_del(Ecore_Event *event)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(event, ECORE_MAGIC_EVENT))
+ {
+ ECORE_MAGIC_FAIL(event, ECORE_MAGIC_EVENT, "ecore_event_del");
+ goto unlock;
+ }
+ EINA_SAFETY_ON_TRUE_GOTO(event->delete_me, unlock);
+ event->delete_me = 1;
+ data = event->data;
+unlock:
+ _ecore_unlock();
+ return data;
+}
+
+EAPI int
+ecore_event_type_new(void)
+{
+ int id;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ _ecore_lock();
+ id = event_id_max++;
+ _ecore_unlock();
+
+ return id;
+}
+
+EAPI Ecore_Event_Filter *
+ecore_event_filter_add(Ecore_Data_Cb func_start,
+ Ecore_Filter_Cb func_filter,
+ Ecore_End_Cb func_end,
+ const void *data)
+{
+ Ecore_Event_Filter *ef = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!func_filter) goto unlock;
+ ef = ecore_event_filter_calloc(1);
+ if (!ef) goto unlock;
+ ECORE_MAGIC_SET(ef, ECORE_MAGIC_EVENT_FILTER);
+ ef->func_start = func_start;
+ ef->func_filter = func_filter;
+ ef->func_end = func_end;
+ ef->data = (void *)data;
+ event_filters = (Ecore_Event_Filter *)eina_inlist_append(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef));
+unlock:
+ _ecore_unlock();
+ return ef;
+}
+
+EAPI void *
+ecore_event_filter_del(Ecore_Event_Filter *ef)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(ef, ECORE_MAGIC_EVENT_FILTER))
+ {
+ ECORE_MAGIC_FAIL(ef, ECORE_MAGIC_EVENT_FILTER, "ecore_event_filter_del");
+ goto unlock;
+ }
+ EINA_SAFETY_ON_TRUE_GOTO(ef->delete_me, unlock);
+ ef->delete_me = 1;
+ event_filters_delete_me = 1;
+ data = ef->data;
+unlock:
+ _ecore_unlock();
+
+ return data;
+}
+
+EAPI int
+ecore_event_current_type_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ return ecore_raw_event_type;
+}
+
+EAPI void *
+ecore_event_current_event_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ return ecore_raw_event_event;
+}
+
+EAPI void *
+_ecore_event_handler_del(Ecore_Event_Handler *event_handler)
+{
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(event_handler->delete_me, NULL);
+ event_handler->delete_me = 1;
+ event_handlers_delete_list = eina_list_append(event_handlers_delete_list, event_handler);
+ return event_handler->data;
+}
+
+void
+_ecore_event_shutdown(void)
+{
+ int i;
+ Ecore_Event_Handler *eh;
+ Ecore_Event_Filter *ef;
+
+ while (events) _ecore_event_del(events);
+ event_current = NULL;
+ for (i = 0; i < event_handlers_num; i++)
+ {
+ while ((eh = event_handlers[i]))
+ {
+ event_handlers[i] = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers[i]), EINA_INLIST_GET(event_handlers[i]));
+ ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE);
+ if (!eh->delete_me) ecore_event_handler_mp_free(eh);
+ }
+ }
+ EINA_LIST_FREE(event_handlers_delete_list, eh)
+ ecore_event_handler_mp_free(eh);
+ if (event_handlers) free(event_handlers);
+ event_handlers = NULL;
+ event_handlers_num = 0;
+ event_handlers_alloc_num = 0;
+ while ((ef = event_filters))
+ {
+ event_filters = (Ecore_Event_Filter *)eina_inlist_remove(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(event_filters));
+ ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE);
+ ecore_event_filter_mp_free(ef);
+ }
+ event_filters_delete_me = 0;
+ event_filter_current = NULL;
+ event_filter_event_current = NULL;
+}
+
+int
+_ecore_event_exist(void)
+{
+ Ecore_Event *e;
+ EINA_INLIST_FOREACH(events, e)
+ if (!e->delete_me) return 1;
+ return 0;
+}
+
+Ecore_Event *
+_ecore_event_add(int type,
+ void *ev,
+ Ecore_End_Cb func_free,
+ void *data)
+{
+ Ecore_Event *e;
+
+ e = ecore_event_calloc(1);
+ if (!e) return NULL;
+ ECORE_MAGIC_SET(e, ECORE_MAGIC_EVENT);
+ e->type = type;
+ e->event = ev;
+ e->func_free = func_free;
+ e->data = data;
+ if (inpurge > 0)
+ {
+ purge_events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(purge_events), EINA_INLIST_GET(e));
+ events_num++;
+ }
+ else
+ {
+ events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), EINA_INLIST_GET(e));
+ events_num++;
+ }
+ return e;
+}
+
+void *
+_ecore_event_del(Ecore_Event *event)
+{
+ void *data;
+
+ data = event->data;
+ if (event->func_free) _ecore_call_end_cb(event->func_free, event->data, event->event);
+ events = (Ecore_Event *)eina_inlist_remove(EINA_INLIST_GET(events), EINA_INLIST_GET(event));
+ ECORE_MAGIC_SET(event, ECORE_MAGIC_NONE);
+ ecore_event_mp_free(event);
+ events_num--;
+ return data;
+}
+
+static void
+_ecore_event_purge_deleted(void)
+{
+ Ecore_Event *itr = events;
+
+ inpurge++;
+ while (itr)
+ {
+ Ecore_Event *next = (Ecore_Event *)EINA_INLIST_GET(itr)->next;
+ if ((!itr->references) && (itr->delete_me))
+ _ecore_event_del(itr);
+ itr = next;
+ }
+ inpurge--;
+ while (purge_events)
+ {
+ Ecore_Event *e = purge_events;
+ purge_events = (Ecore_Event *)eina_inlist_remove(EINA_INLIST_GET(purge_events), EINA_INLIST_GET(purge_events));
+ events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), EINA_INLIST_GET(e));
+ }
+}
+
+static inline void
+_ecore_event_filters_apply()
+{
+ if (!event_filter_current)
+ {
+ /* regular main loop, start from head */
+ event_filter_current = event_filters;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next;
+ }
+
+ while (event_filter_current)
+ {
+ Ecore_Event_Filter *ef = event_filter_current;
+
+ if (!ef->delete_me)
+ {
+ ef->references++;
+
+ if (ef->func_start)
+ ef->loop_data = _ecore_call_data_cb(ef->func_start, ef->data);
+
+ if (!event_filter_event_current)
+ {
+ /* regular main loop, start from head */
+ event_filter_event_current = events;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ event_filter_event_current = (Ecore_Event *)EINA_INLIST_GET(event_filter_event_current)->next;
+ }
+
+ while (event_filter_event_current)
+ {
+ Ecore_Event *e = event_filter_event_current;
+
+ if (!_ecore_call_filter_cb(ef->func_filter, ef->data,
+ ef->loop_data, e->type, e->event))
+ {
+ ecore_event_del(e);
+ }
+
+ if (event_filter_event_current) /* may have changed in recursive main loops */
+ event_filter_event_current = (Ecore_Event *)EINA_INLIST_GET(event_filter_event_current)->next;
+ }
+ if (ef->func_end)
+ _ecore_call_end_cb(ef->func_end, ef->data, ef->loop_data);
+
+ ef->references--;
+ }
+
+ if (event_filter_current) /* may have changed in recursive main loops */
+ event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next;
+ }
+ if (event_filters_delete_me)
+ {
+ int deleted_in_use = 0;
+ Ecore_Event_Filter *l;
+ for (l = event_filters; l; )
+ {
+ Ecore_Event_Filter *ef = l;
+ l = (Ecore_Event_Filter *)EINA_INLIST_GET(l)->next;
+ if (ef->delete_me)
+ {
+ if (ef->references)
+ {
+ deleted_in_use++;
+ continue;
+ }
+
+ event_filters = (Ecore_Event_Filter *)eina_inlist_remove(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef));
+ ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE);
+ ecore_event_filter_mp_free(ef);
+ }
+ }
+ if (!deleted_in_use)
+ event_filters_delete_me = 0;
+ }
+}
+
+void
+_ecore_event_call(void)
+{
+ Eina_List *l, *l_next;
+ Ecore_Event_Handler *eh;
+
+ _ecore_event_filters_apply();
+
+ if (!event_current)
+ {
+ /* regular main loop, start from head */
+ event_current = events;
+ event_handler_current = NULL;
+ }
+
+ while (event_current)
+ {
+ Ecore_Event *e = event_current;
+ int handle_count = 0;
+
+ if (e->delete_me)
+ {
+ event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
+ continue;
+ }
+
+ ecore_raw_event_type = e->type;
+ ecore_raw_event_event = e->event;
+ e->references++;
+ if ((e->type >= 0) && (e->type < event_handlers_num))
+ {
+ if (!event_handler_current)
+ {
+ /* regular main loop, start from head */
+ event_handler_current = event_handlers[e->type];
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ event_handler_current = (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next;
+ }
+
+ while ((event_handler_current) && (!e->delete_me))
+ {
+ eh = event_handler_current;
+ if (!eh->delete_me)
+ {
+ Eina_Bool ret;
+
+ handle_count++;
+
+ eh->references++;
+ ret = _ecore_call_handler_cb(eh->func, eh->data, e->type, e->event);
+ eh->references--;
+
+ if (!ret)
+ {
+ event_handler_current = NULL;
+ break; /* 0 == "call no further handlers" */
+ }
+ }
+
+ if (event_handler_current) /* may have changed in recursive main loops */
+ event_handler_current = (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next;
+ }
+ }
+ while (event_handlers_add_list)
+ {
+ eh = event_handlers_add_list;
+ event_handlers_add_list = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers_add_list), EINA_INLIST_GET(eh));
+ event_handlers[eh->type] = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers[eh->type]), EINA_INLIST_GET(eh));
+ }
+ /* if no handlers were set for EXIT signal - then default is */
+ /* to quit the main loop */
+ if ((e->type == ECORE_EVENT_SIGNAL_EXIT) && (handle_count == 0))
+ ecore_main_loop_quit();
+ e->references--;
+ e->delete_me = 1;
+
+ if (event_current) /* may have changed in recursive main loops */
+ event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
+ }
+
+ ecore_raw_event_type = ECORE_EVENT_NONE;
+ ecore_raw_event_event = NULL;
+
+ _ecore_event_purge_deleted();
+
+ EINA_LIST_FOREACH_SAFE(event_handlers_delete_list, l, l_next, eh)
+ {
+ if (eh->references) continue;
+
+ event_handlers_delete_list = eina_list_remove_list(event_handlers_delete_list, l);
+
+ event_handlers[eh->type] = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers[eh->type]), EINA_INLIST_GET(eh));
+ ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE);
+ ecore_event_handler_mp_free(eh);
+ }
+}
+
+void *
+_ecore_event_signal_user_new(void)
+{
+ Ecore_Event_Signal_User *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Signal_User));
+ return e;
+}
+
+void *
+_ecore_event_signal_hup_new(void)
+{
+ Ecore_Event_Signal_Hup *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Signal_Hup));
+ return e;
+}
+
+void *
+_ecore_event_signal_exit_new(void)
+{
+ Ecore_Event_Signal_Exit *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Signal_Exit));
+ return e;
+}
+
+void *
+_ecore_event_signal_power_new(void)
+{
+ Ecore_Event_Signal_Power *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Signal_Power));
+ return e;
+}
+
+void *
+_ecore_event_signal_realtime_new(void)
+{
+ return calloc(1, sizeof(Ecore_Event_Signal_Realtime));
+}
+
diff --git a/src/lib/ecore/ecore_exe.c b/src/lib/ecore/ecore_exe.c
new file mode 100644
index 0000000000..19bc39b008
--- /dev/null
+++ b/src/lib/ecore/ecore_exe.c
@@ -0,0 +1,1913 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifdef HAVE_SYS_PRCTL_H
+# include <sys/prctl.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* FIXME: Getting respawn to work
+ *
+ * There is no way that we can do anything about the internal state info of
+ * an external exe. The same can be said about the state of user code. User
+ * code in this context means the code that is using ecore_exe to manage exe's
+ * for it.
+ *
+ * Document that the exe must be respawnable, in other words, there is no
+ * state that it cannot regenerate by just killing it and starting it again.
+ * This includes state that the user code knows about, as the respawn is
+ * transparent to that code. On the other hand, maybe a respawn event might
+ * be useful, or maybe resend the currently non existent add event. For
+ * consistancy with ecore_con, an add event is good anyway.
+ *
+ * The Ecore_exe structure is reused for respawning, so that the (opaque)
+ * pointer held by the user remains valid. This means that the Ecore_Exe
+ * init and del functions may need to be split into two parts each to avoid
+ * duplicating code - common code part, and the rest. This implies that
+ * the unchanging members mentioned next should NEVER change.
+ *
+ * These structure members don't need to change -
+ * __list_data - we stay on the list
+ * ECORE_MAGIC - this is a constant
+ * data - passed in originally
+ * cmd - passed in originally
+ * flags - passed in originally
+ *
+ * These structure members need to change -
+ * tag - state that must be regenerated, zap it
+ * pid - it will be different
+ * child_fd_write - it will be different
+ * child_fd_read - it will be different
+ * child_fd_error - it will be different
+ * write_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
+ * read_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
+ * error_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
+ *
+ * Hmm, the read, write, and error buffers could be tricky.
+ * They are not atomic, and could be in a semi complete state.
+ * They fall into the "state must be regenerated" mentioned above.
+ * A respawn/add event should take care of it.
+ *
+ * These structure members need to change -
+ * write_data_buf - state that must be regenerated, zap it
+ * write_data_size - state that must be regenerated, zap it
+ * write_data_offset - state that must be regenerated, zap it
+ * read_data_buf - state that must be regenerated, zap it
+ * read_data_size - state that must be regenerated, zap it
+ * error_data_buf - state that must be regenerated, zap it
+ * error_data_size - state that must be regenerated, zap it
+ * close_write - state that must be regenerated, zap it
+ *
+ * There is the problem that an exe that fell over and needs respawning
+ * might keep falling over, keep needing to be respawned, and tie up system
+ * resources with the constant respawning. An exponentially increasing
+ * timeout (with maximum timeout) between respawns should take care of that.
+ * Although this is not a "contention for a resource" problem, the exe falling
+ * over may be, so a random element added to the timeout may help, and won't
+ * hurt. The user code may need to be informed that a timeout is in progress.
+ */
+
+struct _Ecore_Exe
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ pid_t pid;
+ void *data;
+ char *tag, *cmd;
+ Ecore_Exe_Flags flags;
+ Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to child - if this was used, or NULL if not */
+ Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from child - if this was used, or NULL if not */
+ Ecore_Fd_Handler *error_fd_handler; /* the fd_handler to handle errors from child - if this was used, or NULL if not */
+ void *write_data_buf; /* a data buffer for data to write to the child -
+ * realloced as needed for more data and flushed when the fd handler says writes are possible
+ */
+ int write_data_size; /* the size in bytes of the data buffer */
+ int write_data_offset; /* the offset in bytes in the data buffer */
+ void *read_data_buf; /* data read from the child awating delivery to an event */
+ int read_data_size; /* data read from child in bytes */
+ void *error_data_buf; /* errors read from the child awating delivery to an event */
+ int error_data_size; /* errors read from child in bytes */
+ int child_fd_write; /* fd to write TO to send data to the child */
+ int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */
+ int child_fd_error; /* fd to read FROM when child has sent us (the parent) errors */
+ int child_fd_write_x; /* fd to write TO to send data to the child */
+ int child_fd_read_x; /* fd to read FROM when child has sent us (the parent) data */
+ int child_fd_error_x; /* fd to read FROM when child has sent us (the parent) errors */
+ Eina_Bool close_stdin : 1;
+
+ int start_bytes, end_bytes, start_lines, end_lines; /* Number of bytes/lines to auto pipe at start/end of stdout/stderr. */
+
+ Ecore_Timer *doomsday_clock; /* The Timer of Death. Muahahahaha. */
+ void *doomsday_clock_dead; /* data for the doomsday clock */
+
+ Ecore_Exe_Cb pre_free_cb;
+};
+
+/* TODO: Something to let people build a command line and does auto escaping -
+ *
+ * ecore_exe_snprintf()
+ *
+ * OR
+ *
+ * cmd = ecore_exe_comand_parameter_append(cmd, "firefox");
+ * cmd = ecore_exe_comand_parameter_append(cmd, "http://www.foo.com/bar.html?baz=yes");
+ * each parameter appended is one argument, and it gets escaped, quoted, and
+ * appended with a preceding space. The first is the command off course.
+ */
+
+struct _ecore_exe_dead_exe
+{
+ pid_t pid;
+ char *cmd;
+};
+
+static inline void _ecore_exe_exec_it(const char *exe_cmd,
+ Ecore_Exe_Flags flags);
+static Eina_Bool _ecore_exe_data_generic_handler(void *data,
+ Ecore_Fd_Handler *fd_handler,
+ Ecore_Exe_Flags flags);
+static Eina_Bool _ecore_exe_data_error_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_exe_data_read_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_exe_data_write_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static void _ecore_exe_flush(Ecore_Exe *exe);
+static void _ecore_exe_event_exe_data_free(void *data EINA_UNUSED,
+ void *ev);
+static Ecore_Exe *_ecore_exe_is_it_alive(pid_t pid);
+static Eina_Bool _ecore_exe_make_sure_its_dead(void *data);
+static Eina_Bool _ecore_exe_make_sure_its_really_dead(void *data);
+static Ecore_Exe_Event_Add *_ecore_exe_event_add_new(void);
+static void _ecore_exe_event_add_free(void *data,
+ void *ev);
+static void _ecore_exe_dead_attach(Ecore_Exe *exe);
+
+EAPI int ECORE_EXE_EVENT_ADD = 0;
+EAPI int ECORE_EXE_EVENT_DEL = 0;
+EAPI int ECORE_EXE_EVENT_DATA = 0;
+EAPI int ECORE_EXE_EVENT_ERROR = 0;
+
+static Ecore_Exe *exes = NULL;
+static const char *shell = NULL;
+
+/* FIXME: This errno checking stuff should be put elsewhere for everybody to use.
+ * For now it lives here though, just to make testing easier.
+ */
+static int _ecore_exe_check_errno(int result,
+ const char *file,
+ int line);
+
+#define E_IF_NO_ERRNO(result, foo, ok) \
+ while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1); \
+ if (ok)
+
+#define E_NO_ERRNO(result, foo, ok) \
+ while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1)
+
+#define E_IF_NO_ERRNO_NOLOOP(result, foo, ok) \
+ if (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)))
+
+static int
+_ecore_exe_check_errno(int result,
+ const char *file EINA_UNUSED,
+ int line EINA_UNUSED)
+{
+ int saved_errno = errno;
+
+ if (result == -1)
+ {
+ perror("*** errno reports ");
+/* What is currently supported -
+ *
+ * pipe
+ * EFAULT Argument is not valid.
+ * EMFILE Too many file descriptors used by process.
+ * ENFILE Too many open files by system.
+ * read
+ * EAGAIN No data now, try again.
+ * EBADF This is not an fd that can be read.
+ * EFAULT This is not a valid buffer.
+ * EINTR Interupted by signal, try again.
+ * EINVAL This is not an fd that can be read.
+ * EIO I/O error.
+ * EISDIR This is a directory, and cannot be read.
+ * others Depending on what sort of thing we are reading from.
+ * close
+ * EBADF This is not an fd that can be closed.
+ * EINTR Interupted by signal, try again.
+ * EIO I/O error.
+ * dup2
+ * EBADF This is not an fd that can be dup2'ed.
+ * EBUSY Race condition between open() and dup()
+ * EINTR Interupted by signal, try again.
+ * EMFILE Too many file descriptors used by process.
+ * fcntl
+ * EACCES, EAGAIN Locked or mapped by something else, try again later.
+ * EBADF This is not an fd that can be fcntl'ed.
+ * EDEADLK This will cause a deadlock.
+ * EFAULT This is not a valid lock.
+ * EINTR Interupted by signal, try again.
+ * EINVAL This is not a valid arg.
+ * EMFILE Too many file descriptors used by process.
+ * ENOLCK Problem getting a lock.
+ * EPERM Not allowed to do that.
+ * fsync
+ * EBADF This is not an fd that is open for writing.
+ * EINVAL, EROFS This is not an fd that can be fsynced.
+ * EIO I/O error.
+ *
+ * How to use it -
+ * int ok = 0;
+ * int result;
+ *
+ * E_IF_NO_ERRNO(result, foo(bar), ok)
+ * {
+ * E_IF_NO_ERRNO_NOLOOP(result, foo(bar), ok)
+ * {
+ * }
+ * }
+ *
+ * if (!ok)
+ * {
+ * // Something failed, cleanup.
+ * }
+ */
+ switch (saved_errno)
+ {
+ case EACCES:
+ case EAGAIN:
+ case EINTR:
+ { /* Not now, try later. */
+ ERR("*** Must try again in %s @%u.", file, line);
+ result = -1;
+ break;
+ }
+
+ case EMFILE:
+ case ENFILE:
+ case ENOLCK:
+ { /* Low on resources. */
+ ERR("*** Low on resources in %s @%u.", file,
+ line);
+ result = 0;
+ break;
+ }
+
+ case EIO:
+ { /* I/O error. */
+ ERR("*** I/O error in %s @%u.", file, line);
+ result = 0;
+ break;
+ }
+
+ case EFAULT:
+ case EBADF:
+ case EINVAL:
+ case EROFS:
+ case EISDIR:
+ case EDEADLK:
+ case EPERM:
+ case EBUSY:
+ { /* Programmer fucked up. */
+ ERR("*** NAUGHTY PROGRAMMER!!!\n"
+ "*** SPANK SPANK SPANK!!!\n"
+ "*** Now go fix your code in %s @%u. Tut tut tut!",
+ file, line);
+ result = 0;
+ break;
+ }
+
+ default:
+ { /* Unsupported errno code, please add this one. */
+ ERR("*** NAUGHTY PROGRAMMER!!!\n"
+ "*** SPANK SPANK SPANK!!!\n"
+ "*** Unsupported errno code %d, please add this one.\n"
+ "*** Now go fix your code in %s @%u, from %s @%u. Tut tut tut!",
+ saved_errno, __FILE__, __LINE__, file, line);
+ result = 0;
+ break;
+ }
+ }
+ }
+ else /* Everything is fine. */
+ result = 1;
+
+ errno = saved_errno;
+ return result;
+}
+
+/**
+ * @addtogroup Ecore_Exe_Group
+ *
+ * @{
+ */
+
+static int run_pri = ECORE_EXE_PRIORITY_INHERIT;
+
+/**
+ * Sets the priority at which to launch processes
+ *
+ * This sets the priority of processes run by ecore_exe_run() and
+ * ecore_exe_pipe_run().
+ * @li On Windows, the child process is created by default with the
+ * @ref ECORE_EXE_WIN32_PRIORITY_NORMAL priority, unless the calling
+ * process is in @ref ECORE_EXE_WIN32_PRIORITY_IDLE or
+ * @ref ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL priority. In that case, the
+ * child process inherits this priority.
+ * @li On other platforms, if set to @ref ECORE_EXE_PRIORITY_INHERIT child
+ * processes inherits the priority of their parent. This is the default.
+ *
+ * @param pri value a Ecore_Exe_Win32_Priority value on Windows, -20
+ * to 19 or @ref ECORE_EXE_PRIORITY_INHERIT on other OS.
+ */
+EAPI void
+ecore_exe_run_priority_set(int pri)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ run_pri = pri;
+}
+
+/**
+ * Gets the priority at which to launch processes
+ *
+ * This gets ths priority of launched processes. See
+ * ecore_exe_run_priority_set() for details. This just returns the value set
+ * by this call.
+ *
+ * @return the value set by ecore_exe_run_priority_set()
+ */
+EAPI int
+ecore_exe_run_priority_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ return run_pri;
+}
+
+/**
+ * Spawns a child process.
+ *
+ * This is now just a thin wrapper around ecore_exe_pipe_run()
+ * @note When you use this function you will have no permissions
+ * to write or read on the pipe that connects you with the spwaned process.
+ * If you need to do that use ecore_exe_pipe_run() with the
+ * appropriated flags.
+ *
+ * @param exe_cmd The command to run with @c /bin/sh.
+ * @param data Data to attach to the returned process handle.
+ * @return A process handle to the spawned process.
+ */
+EAPI Ecore_Exe *
+ecore_exe_run(const char *exe_cmd,
+ const void *data)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ return ecore_exe_pipe_run(exe_cmd, 0, data);
+}
+
+/**
+ * Spawns a child process with its stdin/out available for communication.
+ *
+ * This function forks and runs the given command using @c /bin/sh.
+ *
+ * Note that the process handle is only valid until a child process
+ * terminated event is received. After all handlers for the child process
+ * terminated event have been called, the handle will be freed by Ecore.
+ *
+ * This function does the same thing as ecore_exe_run(), but also makes the
+ * standard in and/or out as well as stderr from the child process available
+ * for reading or writing. To write use ecore_exe_send(). To read listen to
+ * ECORE_EXE_EVENT_DATA or ECORE_EXE_EVENT_ERROR events (set up handlers).
+ * Ecore may buffer read and error data until a newline character if asked
+ * for with the @p flags. All data will be included in the events (newlines
+ * will be replaced with NULLS if line buffered). ECORE_EXE_EVENT_DATA events
+ * will only happen if the process is run with ECORE_EXE_PIPE_READ enabled
+ * in the flags. The same with the error version. Writing will only be
+ * allowed with ECORE_EXE_PIPE_WRITE enabled in the flags.
+ *
+ * @param exe_cmd The command to run with @c /bin/sh.
+ * @param flags The flag parameters for how to deal with inter-process I/O
+ * @param data Data to attach to the returned process handle.
+ * @return A process handle to the spawned process.
+ */
+EAPI Ecore_Exe *
+ecore_exe_pipe_run(const char *exe_cmd,
+ Ecore_Exe_Flags flags,
+ const void *data)
+{
+ Ecore_Exe *exe = NULL;
+ int statusPipe[2] = { -1, -1 };
+ int errorPipe[2] = { -1, -1 };
+ int readPipe[2] = { -1, -1 };
+ int writePipe[2] = { -1, -1 };
+ int n = 0;
+ int ok = 1;
+ int result;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!exe_cmd) return NULL;
+ exe = calloc(1, sizeof(Ecore_Exe));
+ if (!exe) return NULL;
+
+ if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
+ && (!(flags & ECORE_EXE_PIPE_READ)))
+ /* We need something to auto pipe. */
+ flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
+
+ exe->child_fd_error = -1;
+ exe->child_fd_read = -1;
+ exe->child_fd_write = -1;
+ exe->child_fd_error_x = -1;
+ exe->child_fd_read_x = -1;
+ exe->child_fd_write_x = -1;
+
+ /* Create some pipes. */
+ if (ok)
+ {
+ E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok)
+ {
+ }
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_ERROR))
+ {
+ E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok)
+ {
+ exe->child_fd_error = errorPipe[0];
+ exe->child_fd_error_x = errorPipe[1];
+ }
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_READ))
+ {
+ E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok)
+ {
+ exe->child_fd_read = readPipe[0];
+ exe->child_fd_read_x = readPipe[1];
+ }
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_WRITE))
+ {
+ E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok)
+ {
+ exe->child_fd_write = writePipe[1];
+ exe->child_fd_write_x = writePipe[0];
+ }
+ }
+ if (ok)
+ {
+ pid_t pid = 0;
+ volatile int vfork_exec_errno = 0;
+
+ /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */
+ /* signal(SIGPIPE, SIG_IGN); We only want EPIPE on errors */
+ pid = fork();
+
+ if (pid == -1)
+ {
+ ERR("Failed to fork process");
+ pid = 0;
+ }
+ else if (pid == 0) /* child */
+ {
+ if (run_pri != ECORE_EXE_PRIORITY_INHERIT)
+ {
+#ifdef PRIO_PROCESS
+ if ((run_pri >= -20) && (run_pri <= 19))
+ setpriority(PRIO_PROCESS, 0, run_pri);
+#else
+#warning "Your OS/libc does not provide PRIO_PROCESS (and possibly setpriority())"
+#warning "This is a POSIX-1.2001 standard and it is highly encouraged that you"
+#warning "Have support for this"
+#endif
+ }
+ /* dup2 STDERR, STDIN, and STDOUT. dup2() allegedly closes the
+ * second pipe if it's open. On the other hand, there was the
+ * Great FD Leak Scare of '06, so let's be paranoid. */
+ if (ok && (flags & ECORE_EXE_PIPE_ERROR))
+ {
+ E_NO_ERRNO(result, close(STDERR_FILENO), ok);
+ E_NO_ERRNO(result, dup2(errorPipe[1], STDERR_FILENO), ok);
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_READ))
+ {
+ E_NO_ERRNO(result, close(STDOUT_FILENO), ok);
+ E_NO_ERRNO(result, dup2(readPipe[1], STDOUT_FILENO), ok);
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_WRITE))
+ {
+ E_NO_ERRNO(result, close(STDIN_FILENO), ok);
+ E_NO_ERRNO(result, dup2(writePipe[0], STDIN_FILENO), ok);
+ }
+
+ if (ok)
+ {
+ /* Setup the status pipe. */
+ E_NO_ERRNO(result, close(statusPipe[0]), ok);
+ E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC), ok) /* close on exec shows success */
+ {
+ /* Run the actual command. */
+ _ecore_exe_exec_it(exe_cmd, flags); /* no return */
+ }
+ }
+
+ /* Something went 'orribly wrong. */
+ vfork_exec_errno = errno;
+
+ /* Close the pipes. */
+ if (flags & ECORE_EXE_PIPE_ERROR)
+ E_NO_ERRNO(result, close(errorPipe[1]), ok);
+ if (flags & ECORE_EXE_PIPE_READ)
+ E_NO_ERRNO(result, close(readPipe[1]), ok);
+ if (flags & ECORE_EXE_PIPE_WRITE)
+ E_NO_ERRNO(result, close(writePipe[0]), ok);
+ E_NO_ERRNO(result, close(statusPipe[1]), ok);
+
+ _exit(-1);
+ }
+ else /* parent */
+ {
+ /* Close the unused pipes. */
+ E_NO_ERRNO(result, close(statusPipe[1]), ok);
+
+ /* FIXME: after having a good look at the current e fd
+ * handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
+ /* FIXME: above F_SETSIG etc. - this is async SIGIO based IO
+ * which is also linux specific so we probably don't want to
+ * do this as long as select() is working fine. the only time
+ * we really want to think of SIGIO async IO is when it all
+ * actually works basically everywhere and we can turn all
+ * IO into DMA async activities (i.e. you do a read() then
+ * the read is complete not on return but when you get a
+ * SIGIO - the read() just starts the transfer and it is
+ * completed in the background by DMA (or whatever mechanism
+ * the kernel choses)) */
+
+ /* Wait for it to start executing. */
+ /* FIXME: this doesn't seem very nice - we sit and block
+ * waiting on a child process... even though it's just
+ * the segment between the fork() and the exec) it just feels
+ * wrong */
+ for (;; )
+ {
+ char buf;
+
+ E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok);
+ if (result == 0)
+ {
+ if (vfork_exec_errno != 0)
+ {
+ n = vfork_exec_errno;
+ ERR("Could not start \"%s\"", exe_cmd);
+ pid = 0;
+ }
+ break;
+ }
+ }
+
+ /* Close the status pipe. */
+ E_NO_ERRNO(result, close(statusPipe[0]), ok);
+ }
+
+ if (pid)
+ {
+ /* Setup the exe structure. */
+ ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
+ exe->start_bytes = -1;
+ exe->end_bytes = -1;
+ exe->start_lines = -1;
+ exe->end_lines = -1;
+ exe->pid = pid;
+ exe->flags = flags;
+ exe->data = (void *)data;
+ if ((exe->cmd = strdup(exe_cmd)))
+ {
+ if (flags & ECORE_EXE_PIPE_ERROR) /* Setup the error stuff. */
+ {
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_error, F_SETFL,
+ O_NONBLOCK), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_error, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_error_x, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ {
+ exe->error_fd_handler =
+ ecore_main_fd_handler_add(exe->child_fd_error,
+ ECORE_FD_READ,
+ _ecore_exe_data_error_handler,
+ exe, NULL, NULL);
+ if (!exe->error_fd_handler)
+ ok = 0;
+ }
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_READ)) /* Setup the read stuff. */
+ {
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_read, F_SETFL,
+ O_NONBLOCK), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_read, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_read_x, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ {
+ exe->read_fd_handler =
+ ecore_main_fd_handler_add(exe->child_fd_read,
+ ECORE_FD_READ,
+ _ecore_exe_data_read_handler,
+ exe, NULL, NULL);
+ if (!exe->read_fd_handler)
+ ok = 0;
+ }
+ }
+ if (ok && (flags & ECORE_EXE_PIPE_WRITE)) /* Setup the write stuff. */
+ {
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_write, F_SETFL,
+ O_NONBLOCK), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_write, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ E_IF_NO_ERRNO(result,
+ fcntl(exe->child_fd_write_x, F_SETFD,
+ FD_CLOEXEC), ok) {
+ }
+ {
+ exe->write_fd_handler =
+ ecore_main_fd_handler_add(exe->child_fd_write,
+ ECORE_FD_WRITE,
+ _ecore_exe_data_write_handler,
+ exe, NULL, NULL);
+ if (exe->write_fd_handler)
+ ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); /* Nothing to write to start with. */
+ else
+ ok = 0;
+ }
+ }
+
+ exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
+ n = 0;
+ }
+ else
+ ok = 0;
+ }
+ else
+ ok = 0;
+ }
+
+ if (!ok) /* Something went wrong, so pull down everything. */
+ {
+ if (exe->pid) ecore_exe_terminate(exe);
+ IF_FN_DEL(ecore_exe_free, exe);
+ }
+ else
+ {
+ Ecore_Exe_Event_Add *e;
+
+ e = _ecore_exe_event_add_new();
+ e->exe = exe;
+ if (e) /* Send the event. */
+ ecore_event_add(ECORE_EXE_EVENT_ADD, e,
+ _ecore_exe_event_add_free, NULL);
+ /* INF("Running as %d for %s.\n", exe->pid, exe->cmd); */
+ }
+
+ errno = n;
+ return exe;
+}
+
+/**
+ * Defines a function to be called before really freeing the handle data.
+ *
+ * This might be useful for language bindings such as Python and Perl
+ * that need to deallocate wrappers associated with this handle.
+ *
+ * This handle should never be modified by this call. It should be
+ * considered informative only. All getters are valid when the given
+ * function is called back.
+ *
+ * @param exe The child process to attach the pre_free function.
+ * @param func The function to call before @a exe is freed.
+ */
+EAPI void
+ecore_exe_callback_pre_free_set(Ecore_Exe *exe,
+ Ecore_Exe_Cb func)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
+ "ecore_exe_callback_pre_free_set");
+ return;
+ }
+ exe->pre_free_cb = func;
+}
+
+/**
+ * Sends data to the given child process which it receives on stdin.
+ *
+ * This function writes to a child processes standard in, with unlimited
+ * buffering. This call will never block. It may fail if the system runs out
+ * of memory.
+ *
+ * @param exe The child process to send to
+ * @param data The data to send
+ * @param size The size of the data to send, in bytes
+ * @return @c EINA_TRUE if successful, @c EINA_FALSE on failure.
+ */
+EAPI Eina_Bool
+ecore_exe_send(Ecore_Exe *exe,
+ const void *data,
+ int size)
+{
+ void *buf;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send");
+ return EINA_FALSE;
+ }
+
+ if (exe->close_stdin)
+ {
+ ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
+ exe, size, data);
+ return EINA_FALSE;
+ }
+
+ if (exe->child_fd_write == -1)
+ {
+ ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! "
+ "Cannot send %d bytes from %p", exe, size, data);
+ return EINA_FALSE;
+ }
+
+ buf = realloc(exe->write_data_buf, exe->write_data_size + size);
+ if (!buf) return EINA_FALSE;
+
+ exe->write_data_buf = buf;
+ memcpy((char *)exe->write_data_buf + exe->write_data_size, data, size);
+ exe->write_data_size += size;
+
+ if (exe->write_fd_handler)
+ ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE);
+
+ return EINA_TRUE;
+}
+
+/**
+ * The stdin of the given child process will close when the write buffer is empty.
+ *
+ * @param exe The child process
+ */
+EAPI void
+ecore_exe_close_stdin(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin");
+ return;
+ }
+ exe->close_stdin = 1;
+}
+
+/**
+ * Sets the auto pipe limits for the given process handle. On Windows
+ * this function does nothing.
+ *
+ * @param exe The given process handle.
+ * @param start_bytes limit of bytes at start of output to buffer.
+ * @param end_bytes limit of bytes at end of output to buffer.
+ * @param start_lines limit of lines at start of output to buffer.
+ * @param end_lines limit of lines at end of output to buffer.
+ */
+EAPI void
+ecore_exe_auto_limits_set(Ecore_Exe *exe,
+ int start_bytes,
+ int end_bytes,
+ int start_lines,
+ int end_lines)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_auto_limits_set");
+ return;
+ }
+ /* FIXME: sanitize the input. */
+ exe->start_bytes = start_bytes;
+ exe->end_bytes = end_bytes;
+ exe->start_lines = start_lines;
+ exe->end_lines = end_lines;
+
+ /* FIXME: get this can of worms working.
+ *
+ * capture stderr & stdout internally
+ *
+ * raster and onefang keep moving the goal posts on this one. It started out as
+ * "show users the error output if an exe fails" and is rapidly approaching
+ * "alternative method of getting the data, poll vs event driven". Some serious
+ * thinking needs to be applied to this. Do we really want to go that far? If
+ * so, we should change the names. The basic design will probably remain the
+ * same which ever way we go. The constant goal post moving is probably due to
+ * generic design methods leading to feature creep as we inspired each other to
+ * more generic designs. It does seem like the closer we get to poll driven,
+ * the more issues and corner cases there are.
+ *
+ * Instead of doing the usual register an event handler thing, we are ecore_exe,
+ * we can take some short cuts. Don't send the events, just leave the exe buffers
+ * as is until the user asks for them, then return the event.
+ *
+ * start = 0, end = 0; clogged arteries get flushed, everything is ignored.
+ * start = -1, end = -1; clogged arteries get transferred to internal buffers. Actually, either == -1 means buffer everything.
+ * start = X, end = 0; buffer first X out of clogged arteries, flush and ignore rest.
+ * start = 0, end = X; circular buffer X
+ * start = X, end = Y; buffer first X out of clogged arteries, circular buffer Y from beginning.
+ *
+ * bytes vs lines, which ever one reaches the limit first.
+ * Before we go beyond the start+end limit, leave the end buffer empty, and store both in the start buffer, coz they overlap.
+ * After we pass the the start+end limit, insert "\n...\n" at the end of the start buffer, copy the rest to the end buffer, then store in the end buffer.
+ *
+ * Other issues -
+ * Spank programmer for polling data if polling is not turned on.
+ * Spank programmer for setting up event callbacks if polling is turned on.
+ * Spank programmer for freeing the event data if it came from the event system, as that autofrees.
+ * Spank the programmer if they try to set the limits bigger than what has been gathered & ignored already, coz they just lost data.
+ * Spank onefang and raster for opening this can of worms.
+ * Should we have separate out/err limits?
+ * Should we remove from the internal buffer the data that was delivered already?
+ * If so, what to do about limits, start, and end? They could loose their meaning.
+ */
+}
+
+/**
+ * Gets the auto pipe data for the given process handle
+ *
+ * @param exe The given process handle.
+ * @param flags Is this a ECORE_EXE_PIPE_READ or ECORE_EXE_PIPE_ERROR?
+ * @return The event data.
+ */
+EAPI Ecore_Exe_Event_Data *
+ecore_exe_event_data_get(Ecore_Exe *exe,
+ Ecore_Exe_Flags flags)
+{
+ Ecore_Exe_Event_Data *e = NULL;
+ int is_buffered = 0;
+ unsigned char *inbuf;
+ int inbuf_num;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get");
+ return NULL;
+ }
+
+ /* Sort out what sort of event we are. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ flags = ECORE_EXE_PIPE_READ;
+ if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED)
+ is_buffered = 1;
+ }
+ else
+ {
+ flags = ECORE_EXE_PIPE_ERROR;
+ if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED)
+ is_buffered = 1;
+ }
+
+ /* Get the data. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ inbuf = exe->read_data_buf;
+ inbuf_num = exe->read_data_size;
+ exe->read_data_buf = NULL;
+ exe->read_data_size = 0;
+ }
+ else
+ {
+ inbuf = exe->error_data_buf;
+ inbuf_num = exe->error_data_size;
+ exe->error_data_buf = NULL;
+ exe->error_data_size = 0;
+ }
+
+ e = calloc(1, sizeof(Ecore_Exe_Event_Data));
+ if (e)
+ {
+ e->exe = exe;
+ e->data = inbuf;
+ e->size = inbuf_num;
+
+ if (is_buffered) /* Deal with line buffering. */
+ {
+ int max = 0;
+ int count = 0;
+ int i;
+ int last = 0;
+ char *c;
+
+ c = (char *)inbuf;
+ for (i = 0; i < inbuf_num; i++) /* Find the lines. */
+ {
+ if (inbuf[i] == '\n')
+ {
+ if (count >= max)
+ {
+ /* In testing, the lines seem to arrive in batches of 500 to 1000 lines at most, roughly speaking. */
+ max += 10; /* FIXME: Maybe keep track of the largest number of lines ever sent, and add half that many instead of 10. */
+ e->lines = realloc(e->lines, sizeof(Ecore_Exe_Event_Data_Line) * (max + 1)); /* Allow room for the NULL termination. */
+ }
+ /* raster said to leave the line endings as line endings, however -
+ * This is line buffered mode, we are not dealing with binary here, but lines.
+ * If we are not dealing with binary, we must be dealing with ASCII, unicode, or some other text format.
+ * Thus the user is most likely gonna deal with this text as strings.
+ * Thus the user is most likely gonna pass this data to str functions.
+ * rasters way - the endings are always gonna be '\n'; onefangs way - they will always be '\0'
+ * We are handing them the string length as a convenience.
+ * Thus if they really want it in raw format, they can e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough.
+ * In the default case, we can do this conversion quicker than the user can, as we already have the index and pointer.
+ * Let's make it easy on them to use these as standard C strings.
+ *
+ * onefang is proud to announce that he has just set a new personal record for the
+ * most over documentation of a simple assignment statement. B-)
+ */
+ inbuf[i] = '\0';
+ e->lines[count].line = c;
+ e->lines[count].size = i - last;
+ last = i + 1;
+ c = (char *)&inbuf[last];
+ count++;
+ }
+ }
+ if (i > last) /* Partial line left over, save it for next time. */
+ {
+ if (count != 0) e->size = last;
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ exe->read_data_size = i - last;
+ exe->read_data_buf = malloc(exe->read_data_size);
+ memcpy(exe->read_data_buf, c, exe->read_data_size);
+ }
+ else
+ {
+ exe->error_data_size = i - last;
+ exe->error_data_buf = malloc(exe->error_data_size);
+ memcpy(exe->error_data_buf, c, exe->error_data_size);
+ }
+ }
+ if (count == 0) /* No lines to send, cancel the event. */
+ {
+ _ecore_exe_event_exe_data_free(NULL, e);
+ e = NULL;
+ }
+ else /* NULL terminate the array, so that people know where the end is. */
+ {
+ e->lines[count].line = NULL;
+ e->lines[count].size = 0;
+ }
+ }
+ }
+
+ return e;
+}
+
+/**
+ * Sets the string tag for the given process handle
+ *
+ * @param exe The given process handle.
+ * @param tag The string tag to set on the process handle.
+ */
+EAPI void
+ecore_exe_tag_set(Ecore_Exe *exe,
+ const char *tag)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set");
+ return;
+ }
+ IF_FREE(exe->tag);
+ if (tag)
+ exe->tag = strdup(tag);
+ else
+ exe->tag = NULL;
+}
+
+/**
+ * Retrieves the tag attached to the given process handle. There is no need to
+ * free it as it just returns the internal pointer value. This value is only
+ * valid as long as the @p exe is valid or until the tag is set to something
+ * else on this @p exe.
+ *
+ * @param exe The given process handle.
+ * @return The string attached to @p exe. It is a handle to existing
+ * internal string and should not be modified, use
+ * ecore_exe_tag_set() to change it. It might be @c NULL.
+ */
+EAPI const char *
+ecore_exe_tag_get(const Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get");
+ return NULL;
+ }
+ return exe->tag;
+}
+
+/**
+ * Frees the given process handle.
+ *
+ * Note that the process that the handle represents is unaffected by this
+ * function.
+ *
+ * @param exe The given process handle.
+ * @return The data attached to the handle when @ref ecore_exe_run was
+ * called.
+ */
+EAPI void *
+ecore_exe_free(Ecore_Exe *exe)
+{
+ void *data;
+ int ok = 0;
+ int result;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free");
+ return NULL;
+ }
+
+ data = exe->data;
+
+ if (exe->pre_free_cb)
+ exe->pre_free_cb(data, exe);
+
+ if (exe->doomsday_clock)
+ {
+ struct _ecore_exe_dead_exe *dead;
+
+ ecore_timer_del(exe->doomsday_clock);
+ exe->doomsday_clock = NULL;
+ dead = exe->doomsday_clock_dead;
+ if (dead)
+ {
+ IF_FREE(dead->cmd);
+ free(dead);
+ exe->doomsday_clock_dead = NULL;
+ }
+ }
+ IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
+ IF_FN_DEL(ecore_main_fd_handler_del, exe->read_fd_handler);
+ IF_FN_DEL(ecore_main_fd_handler_del, exe->error_fd_handler);
+ if (exe->child_fd_write_x != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_write_x), ok);
+ if (exe->child_fd_read_x != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_read_x), ok);
+ if (exe->child_fd_error_x != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_error_x), ok);
+ if (exe->child_fd_write != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_write), ok);
+ if (exe->child_fd_read != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_read), ok);
+ if (exe->child_fd_error != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_error), ok);
+ IF_FREE(exe->write_data_buf);
+ IF_FREE(exe->read_data_buf);
+ IF_FREE(exe->error_data_buf);
+ IF_FREE(exe->cmd);
+
+ exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
+ ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE);
+ IF_FREE(exe->tag);
+ free(exe);
+ return data;
+}
+
+/**
+ * Frees the given event data.
+ *
+ * @param e The given event data.
+ */
+EAPI void
+ecore_exe_event_data_free(Ecore_Exe_Event_Data *e)
+{
+ if (!e) return;
+ IF_FREE(e->lines);
+ IF_FREE(e->data);
+ free(e);
+}
+
+/**
+ * Retrieves the process ID of the given spawned process.
+ * @param exe Handle to the given spawned process.
+ * @return The process ID on success. @c -1 otherwise.
+ */
+EAPI pid_t
+ecore_exe_pid_get(const Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get");
+ return -1;
+ }
+ return exe->pid;
+}
+
+/**
+ * Retrieves the command of the given spawned process.
+ * @param exe Handle to the given spawned process.
+ * @return The command on success, @c NULL otherwise. This string is the
+ * pointer to the internal value and must not be modified in
+ * any way.
+ */
+EAPI const char *
+ecore_exe_cmd_get(const Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get");
+ return NULL;
+ }
+ return exe->cmd;
+}
+
+/**
+ * Retrieves the data attached to the given process handle.
+ * @param exe The given process handle.
+ * @return The data pointer attached to @p exe Given to
+ * ecore_exe_run() or ecore_exe_pipe_run()
+ */
+EAPI void *
+ecore_exe_data_get(const Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+ return NULL;
+ }
+ return exe->data;
+}
+
+/**
+ * Sets the data attached to the given process handle.
+ * @param exe The given process handle.
+ * @param data The pointer to attach
+ * @return The data pointer previously attached to @p exe with
+ * ecore_exe_run(), ecore_exe_pipe_run(), or ecore_exe_data_set()
+ * @since 1.1
+ */
+EAPI void *
+ecore_exe_data_set(Ecore_Exe *exe,
+ void *data)
+{
+ void *ret;
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, __func__);
+ return NULL;
+ }
+ ret = exe->data;
+ exe->data = data;
+ return ret;
+}
+
+/**
+ * Retrieves the flags attached to the given process handle.
+ * @param exe The given process handle.
+ * @return The flags attached to @p exe.
+ */
+EAPI Ecore_Exe_Flags
+ecore_exe_flags_get(const Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+ return 0;
+ }
+ return exe->flags;
+}
+
+/**
+ * Pauses the given process by sending it a @c SIGSTOP signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_pause(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause");
+ return;
+ }
+ kill(exe->pid, SIGSTOP);
+}
+
+/**
+ * Continues the given paused process by sending it a @c SIGCONT signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_continue(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue");
+ return;
+ }
+ kill(exe->pid, SIGCONT);
+}
+
+/**
+ * Sends the given spawned process a interrupt (@c SIGINT) signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_interrupt(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt");
+ return;
+ }
+ _ecore_exe_dead_attach(exe);
+ kill(exe->pid, SIGINT);
+}
+
+/**
+ * Sends the given spawned process a quit (@c SIGQUIT) signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_quit(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit");
+ return;
+ }
+ _ecore_exe_dead_attach(exe);
+ kill(exe->pid, SIGQUIT);
+}
+
+/**
+ * Sends the given spawned process a terminate (@c SIGTERM) signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_terminate(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate");
+ return;
+ }
+ _ecore_exe_dead_attach(exe);
+ INF("Sending TERM signal to %s (%d).", exe->cmd, exe->pid);
+ kill(exe->pid, SIGTERM);
+}
+
+/**
+ * Kills the given spawned process by sending it a @c SIGKILL signal.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_kill(Ecore_Exe *exe)
+{
+ struct _ecore_exe_dead_exe *dead;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill");
+ return;
+ }
+
+ dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
+ if (dead)
+ {
+ dead->pid = exe->pid;
+ dead->cmd = strdup(exe->cmd);
+ IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
+ exe->doomsday_clock =
+ ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead, dead);
+ }
+
+ INF("Sending KILL signal to %s (%d).", exe->cmd, exe->pid);
+ kill(exe->pid, SIGKILL);
+}
+
+/**
+ * Sends a @c SIGUSR signal to the given spawned process.
+ * @param exe Process handle to the given process.
+ * @param num The number user signal to send. Must be either 1 or 2, or
+ * the signal will be ignored.
+ */
+EAPI void
+ecore_exe_signal(Ecore_Exe *exe,
+ int num)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal");
+ return;
+ }
+ if (num == 1)
+ kill(exe->pid, SIGUSR1);
+ else if (num == 2)
+ kill(exe->pid, SIGUSR2);
+}
+
+/**
+ * Sends a @c SIGHUP signal to the given spawned process.
+ * @param exe Process handle to the given process.
+ */
+EAPI void
+ecore_exe_hup(Ecore_Exe *exe)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup");
+ return;
+ }
+ kill(exe->pid, SIGHUP);
+}
+
+/**
+ * @}
+ */
+
+static Ecore_Exe *
+_ecore_exe_is_it_alive(pid_t pid)
+{
+ Ecore_Exe *exe = NULL;
+
+ /* FIXME: There is no nice, safe, OS independent way to tell if a
+ * particular PID is still alive. I have written code to do so
+ * for my urunlevel busybox applet (http://urunlevel.sourceforge.net/),
+ * but it's for linux only, and still not guaranteed.
+ *
+ * So for now, we just check that a valid Ecore_Exe structure
+ * exists for it. Even that is not a guarantee, as the structure
+ * can be freed without killing the process.
+ *
+ * I think we can safely put exe's into two categories, those users
+ * that care about the life of the exe, and the run and forget type.
+ * The run and forget type starts up the exe, then free's the
+ * Ecore_Exe structure straight away. They can never call any of
+ * the functions that can call this, so we don't worry about them.
+ *
+ * Those user's that care about the life of exe's will keep the
+ * Ecore_Exe structure around, terminate them eventually, or
+ * register for exit events. For these ones the assumption
+ * that valid Ecore_Exe struct == live exe is almost valid.
+ *
+ * I will probably copy my urunlevel code into here someday.
+ */
+ exe = _ecore_exe_find(pid);
+ if (exe)
+ {
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ exe = NULL;
+ }
+
+ return exe;
+}
+
+static Eina_Bool
+_ecore_exe_make_sure_its_dead(void *data)
+{
+ struct _ecore_exe_dead_exe *dead;
+
+ dead = data;
+ if (dead)
+ {
+ Ecore_Exe *exe = NULL;
+
+ if ((exe = _ecore_exe_is_it_alive(dead->pid)))
+ {
+ if (dead->cmd)
+ INF("Sending KILL signal to allegedly dead %s (%d).",
+ dead->cmd, dead->pid);
+ else
+ INF("Sending KILL signal to allegedly dead PID %d.",
+ dead->pid);
+ exe->doomsday_clock =
+ ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead,
+ dead);
+ kill(dead->pid, SIGKILL);
+ }
+ else
+ {
+ IF_FREE(dead->cmd);
+ free(dead);
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_exe_make_sure_its_really_dead(void *data)
+{
+ struct _ecore_exe_dead_exe *dead;
+
+ dead = data;
+ if (dead)
+ {
+ Ecore_Exe *exe = NULL;
+
+ if ((exe = _ecore_exe_is_it_alive(dead->pid)))
+ {
+ ERR("RUN! The zombie wants to eat your brains! And your CPU!");
+ if (dead->cmd)
+ INF("%s (%d) is not really dead.", dead->cmd, dead->pid);
+ else
+ INF("PID %d is not really dead.", dead->pid);
+ exe->doomsday_clock = NULL;
+ }
+ IF_FREE(dead->cmd);
+ free(dead);
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+void
+_ecore_exe_init(void)
+{
+ ECORE_EXE_EVENT_ADD = ecore_event_type_new();
+ ECORE_EXE_EVENT_DEL = ecore_event_type_new();
+ ECORE_EXE_EVENT_DATA = ecore_event_type_new();
+ ECORE_EXE_EVENT_ERROR = ecore_event_type_new();
+}
+
+void
+_ecore_exe_shutdown(void)
+{
+ while (exes)
+ ecore_exe_free(exes);
+}
+
+Ecore_Exe *
+_ecore_exe_find(pid_t pid)
+{
+ Ecore_Exe *exe;
+
+ EINA_INLIST_FOREACH(exes, exe)
+ {
+ if (exe->pid == pid)
+ return exe;
+ }
+ return NULL;
+}
+
+Ecore_Timer *
+_ecore_exe_doomsday_clock_get(Ecore_Exe *exe)
+{
+ return exe->doomsday_clock;
+}
+
+void
+_ecore_exe_doomsday_clock_set(Ecore_Exe *exe,
+ Ecore_Timer *dc)
+{
+ exe->doomsday_clock = dc;
+}
+
+static inline void
+_ecore_exe_exec_it(const char *exe_cmd,
+ Ecore_Exe_Flags flags)
+{
+ char use_sh = 1;
+ char *buf = NULL;
+ char **args = NULL;
+ int save_errno = 0;
+
+ /* So what is this doing?
+ *
+ * We are trying to avoid wrapping the exe call with /bin/sh -c.
+ * We conservatively search for certain shell meta characters,
+ * If we don't find them, we can call the exe directly.
+ */
+ if (!strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#"))
+ {
+ char *token;
+ char pre_command = 1;
+ int num_tokens = 0;
+
+ if (!(buf = strdup(exe_cmd)))
+ return;
+
+ token = strtok(buf, " \t\n\v");
+ while (token)
+ {
+ if (token[0] == '~')
+ break;
+ if (pre_command)
+ {
+ if (token[0] == '[')
+ break;
+ if (strchr(token, '='))
+ break;
+ else
+ pre_command = 0;
+ }
+ num_tokens++;
+ token = strtok(NULL, " \t\n\v");
+ }
+ IF_FREE(buf);
+ if ((!token) && (num_tokens))
+ {
+ int i = 0;
+
+ if (!(buf = strdup(exe_cmd)))
+ return;
+
+ token = strtok(buf, " \t\n\v");
+ use_sh = 0;
+ if (!(args = (char **)calloc(num_tokens + 1, sizeof(char *))))
+ {
+ IF_FREE(buf);
+ return;
+ }
+ for (i = 0; i < num_tokens; i++)
+ {
+ if (token)
+ args[i] = token;
+ token = strtok(NULL, " \t\n\v");
+ }
+ args[num_tokens] = NULL;
+ }
+ }
+
+#ifdef HAVE_SYS_PRCTL_H
+ if ((flags & ECORE_EXE_TERM_WITH_PARENT))
+ {
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+ }
+#endif
+
+ if (!(flags & ECORE_EXE_NOT_LEADER)) setsid();
+ if ((flags & ECORE_EXE_USE_SH))
+ {
+ errno = 0;
+ execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL);
+ }
+ else if (use_sh) /* We have to use a shell to run this. */
+ {
+ if (!shell) /* Find users preferred shell. */
+ {
+ shell = getenv("SHELL");
+ if (!shell)
+ shell = "/bin/sh";
+ }
+ errno = 0;
+ execl(shell, shell, "-c", exe_cmd, (char *)NULL);
+ }
+ else
+ { /* We can run this directly. */
+ if (!args)
+ {
+ IF_FREE(buf);
+ IF_FREE(args);
+ ERR("arg[0] is NULL!");
+ return;
+ }
+ errno = 0;
+ execvp(args[0], args);
+ }
+
+ save_errno = errno;
+ IF_FREE(buf);
+ IF_FREE(args);
+ errno = save_errno;
+ return;
+}
+
+static Eina_Bool
+_ecore_exe_data_generic_handler(void *data,
+ Ecore_Fd_Handler *fd_handler,
+ Ecore_Exe_Flags flags)
+{
+ Ecore_Exe *exe;
+ int child_fd;
+ int event_type;
+
+ exe = data;
+
+ /* Sort out what sort of handler we are. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ flags = ECORE_EXE_PIPE_READ;
+ event_type = ECORE_EXE_EVENT_DATA;
+ child_fd = exe->child_fd_read;
+ }
+ else
+ {
+ flags = ECORE_EXE_PIPE_ERROR;
+ event_type = ECORE_EXE_EVENT_ERROR;
+ child_fd = exe->child_fd_error;
+ }
+
+ if ((fd_handler)
+ && (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)))
+ {
+ unsigned char *inbuf;
+ int inbuf_num;
+
+ /* Get any left over data from last time. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ inbuf = exe->read_data_buf;
+ inbuf_num = exe->read_data_size;
+ exe->read_data_buf = NULL;
+ exe->read_data_size = 0;
+ }
+ else
+ {
+ inbuf = exe->error_data_buf;
+ inbuf_num = exe->error_data_size;
+ exe->error_data_buf = NULL;
+ exe->error_data_size = 0;
+ }
+
+ for (;; )
+ {
+ int num, lost_exe;
+ char buf[READBUFSIZ];
+
+ lost_exe = 0;
+ errno = 0;
+ if ((num = read(child_fd, buf, READBUFSIZ)) < 1)
+ {
+ /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE
+ * (currently 64k) to inbuf, use that instead of buf, and
+ * save ourselves a memcpy(). */
+ lost_exe = ((errno == EIO) ||
+ (errno == EBADF) ||
+ (errno == EPIPE) ||
+ (errno == EINVAL) || (errno == ENOSPC));
+ if ((errno != EAGAIN) && (errno != EINTR))
+ perror("_ecore_exe_generic_handler() read problem ");
+ }
+ if (num > 0) /* data got read. */
+ {
+ inbuf = realloc(inbuf, inbuf_num + num);
+ memcpy(inbuf + inbuf_num, buf, num);
+ inbuf_num += num;
+ }
+ else
+ { /* No more data to read. */
+ if (inbuf)
+ {
+ Ecore_Exe_Event_Data *e;
+
+ /* Stash the data away for later. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ exe->read_data_buf = inbuf;
+ exe->read_data_size = inbuf_num;
+ }
+ else
+ {
+ exe->error_data_buf = inbuf;
+ exe->error_data_size = inbuf_num;
+ }
+
+ if (!(exe->flags & ECORE_EXE_PIPE_AUTO))
+ {
+ e = ecore_exe_event_data_get(exe, flags);
+ if (e) /* Send the event. */
+ ecore_event_add(event_type, e,
+ _ecore_exe_event_exe_data_free,
+ NULL);
+ }
+ }
+ if (lost_exe)
+ {
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ if (exe->read_data_size)
+ INF("There are %d bytes left unsent from the dead exe %s.",
+ exe->read_data_size, exe->cmd);
+ }
+ else
+ {
+ if (exe->error_data_size)
+ INF("There are %d bytes left unsent from the dead exe %s.",
+ exe->error_data_size, exe->cmd);
+ }
+ /* Thought about this a bit. If the exe has actually
+ * died, this won't do any harm as it must have died
+ * recently and the pid has not had a chance to recycle.
+ * It is also a paranoid catchall, coz the usual ecore_signal
+ * mechenism should kick in. But let's give it a good
+ * kick in the head anyway.
+ */
+ ecore_exe_terminate(exe);
+ }
+ break;
+ }
+ }
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_exe_data_error_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ return _ecore_exe_data_generic_handler(data, fd_handler,
+ ECORE_EXE_PIPE_ERROR);
+}
+
+static Eina_Bool
+_ecore_exe_data_read_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ return _ecore_exe_data_generic_handler(data, fd_handler,
+ ECORE_EXE_PIPE_READ);
+}
+
+static Eina_Bool
+_ecore_exe_data_write_handler(void *data,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Ecore_Exe *exe;
+
+ exe = data;
+ if ((exe->write_fd_handler) &&
+ (ecore_main_fd_handler_active_get
+ (exe->write_fd_handler, ECORE_FD_WRITE)))
+ _ecore_exe_flush(exe);
+
+ /* If we have sent all there is to send, and we need to close the pipe, then close it. */
+ if ((exe->close_stdin == 1)
+ && (exe->write_data_size == exe->write_data_offset))
+ {
+ int ok = 0;
+ int result;
+
+ INF("Closing stdin for %s", exe->cmd);
+ /* if (exe->child_fd_write != -1) E_NO_ERRNO(result, fsync(exe->child_fd_write), ok); This a) doesn't work, and b) isn't needed. */
+ IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
+ if (exe->child_fd_write != -1)
+ E_NO_ERRNO(result, close(exe->child_fd_write), ok);
+ exe->child_fd_write = -1;
+ IF_FREE(exe->write_data_buf);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_exe_flush(Ecore_Exe *exe)
+{
+ int count;
+
+ /* check whether we need to write anything at all. */
+ if ((exe->child_fd_write == -1) || (!exe->write_data_buf))
+ return;
+ if (exe->write_data_size == exe->write_data_offset)
+ return;
+
+ count = write(exe->child_fd_write,
+ (char *)exe->write_data_buf + exe->write_data_offset,
+ exe->write_data_size - exe->write_data_offset);
+ if (count < 1)
+ {
+ if (errno == EIO || errno == EBADF || errno == EPIPE || errno == EINVAL || errno == ENOSPC) /* we lost our exe! */
+ {
+ ecore_exe_terminate(exe);
+ if (exe->write_fd_handler)
+ ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
+ }
+ }
+ else
+ {
+ exe->write_data_offset += count;
+ if (exe->write_data_offset >= exe->write_data_size) /* Nothing left to write, clean up. */
+ {
+ exe->write_data_size = 0;
+ exe->write_data_offset = 0;
+ IF_FREE(exe->write_data_buf);
+ if (exe->write_fd_handler)
+ ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
+ }
+ }
+}
+
+static void
+_ecore_exe_event_exe_data_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Data *e;
+
+ e = ev;
+ ecore_exe_event_data_free(e);
+}
+
+static Ecore_Exe_Event_Add *
+_ecore_exe_event_add_new(void)
+{
+ Ecore_Exe_Event_Add *e;
+
+ e = calloc(1, sizeof(Ecore_Exe_Event_Add));
+ return e;
+}
+
+static void
+_ecore_exe_event_add_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Add *e;
+
+ e = ev;
+ free(e);
+}
+
+void *
+_ecore_exe_event_del_new(void)
+{
+ Ecore_Exe_Event_Del *e;
+
+ e = calloc(1, sizeof(Ecore_Exe_Event_Del));
+ return e;
+}
+
+void
+_ecore_exe_event_del_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Del *e;
+
+ e = ev;
+ if (e->exe)
+ ecore_exe_free(e->exe);
+ free(e);
+}
+
+static void
+_ecore_exe_dead_attach(Ecore_Exe *exe)
+{
+ struct _ecore_exe_dead_exe *dead;
+
+ if (exe->doomsday_clock_dead) return;
+ dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
+ if (dead)
+ {
+ dead->pid = exe->pid;
+ dead->cmd = strdup(exe->cmd);
+ IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
+ exe->doomsday_clock =
+ ecore_timer_add(10.0, _ecore_exe_make_sure_its_dead, dead);
+ exe->doomsday_clock_dead = dead;
+ }
+}
+
diff --git a/src/lib/ecore/ecore_exe_ps3.c b/src/lib/ecore/ecore_exe_ps3.c
new file mode 100644
index 0000000000..1ef1e81fcb
--- /dev/null
+++ b/src/lib/ecore/ecore_exe_ps3.c
@@ -0,0 +1,20 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ESCAPE
+# include <Escape.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+void
+_ecore_exe_init(void)
+{
+}
+
+void
+_ecore_exe_shutdown(void)
+{
+}
diff --git a/src/lib/ecore/ecore_exe_win32.c b/src/lib/ecore/ecore_exe_win32.c
new file mode 100644
index 0000000000..71557c3676
--- /dev/null
+++ b/src/lib/ecore/ecore_exe_win32.c
@@ -0,0 +1,1055 @@
+/*
+ * TODO:
+ * - manage I/O pipes (several ones, and stdin)
+ * - manage SetConsoleCtrlHandler ?
+ * - the child process seems to still run after the DEL event
+ * - add log messages
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <process.h>
+
+#define ECORE_EXE_WIN32_TIMEOUT 3000
+
+typedef enum
+{
+ ECORE_EXE_WIN32_SIGINT,
+ ECORE_EXE_WIN32_SIGQUIT,
+ ECORE_EXE_WIN32_SIGTERM,
+ ECORE_EXE_WIN32_SIGKILL
+} Ecore_Exe_Win32_Signal;
+
+struct _Ecore_Exe
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+
+ HANDLE process2;
+ HANDLE process; /* CloseHandle */
+ HANDLE process_thread;
+ DWORD process_id;
+ DWORD thread_id;
+ void *data;
+ char *tag;
+ char *cmd;
+ Ecore_Exe_Flags flags;
+ Ecore_Exe_Win32_Signal sig;
+ Ecore_Win32_Handler *h_close;
+ struct
+ {
+ HANDLE child_pipe;
+ HANDLE child_pipe_x;
+ Ecore_Pipe *p;
+ HANDLE thread;
+ void *data_buf;
+ int data_size;
+ } pipe_read;
+ struct
+ {
+ HANDLE child_pipe;
+ HANDLE child_pipe_x;
+ HANDLE thread;
+ Ecore_Win32_Handler *h;
+ void *data_buf;
+ int data_size;
+ } pipe_write;
+ struct
+ {
+ HANDLE child_pipe;
+ HANDLE child_pipe_x;
+ Ecore_Pipe *p;
+ HANDLE thread;
+ void *data_buf;
+ int data_size;
+ } pipe_error;
+ Eina_Bool close_stdin : 1;
+ Eina_Bool is_suspended : 1;
+
+ Ecore_Exe_Cb pre_free_cb;
+};
+
+static Ecore_Exe *exes = NULL;
+
+static int _ecore_exe_win32_pipes_set(Ecore_Exe *exe);
+static void _ecore_exe_win32_pipes_close(Ecore_Exe *exe);
+
+static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window,
+ LPARAM data);
+static void _ecore_exe_event_add_free(void *data,
+ void *ev);
+static void _ecore_exe_event_del_free(void *data,
+ void *ev);
+static void _ecore_exe_event_exe_data_free(void *data,
+ void *ev);
+static int _ecore_exe_win32_pipe_thread_generic_cb(void *data,
+ Ecore_Exe_Flags flags);
+static DWORD WINAPI _ecore_exe_win32_pipe_thread_read_cb(void *data);
+static DWORD WINAPI _ecore_exe_win32_pipe_thread_error_cb(void *data);
+static Eina_Bool _ecore_exe_close_cb(void *data,
+ Ecore_Win32_Handler *wh);
+static void _ecore_exe_pipe_read_cb(void *data,
+ void *buf,
+ unsigned int size);
+static int _ecore_exe_pipe_write_cb(void *data,
+ Ecore_Win32_Handler *wh);
+static void _ecore_exe_pipe_error_cb(void *data,
+ void *buf,
+ unsigned int size);
+
+EAPI int ECORE_EXE_EVENT_ADD = 0;
+EAPI int ECORE_EXE_EVENT_DEL = 0;
+EAPI int ECORE_EXE_EVENT_DATA = 0;
+EAPI int ECORE_EXE_EVENT_ERROR = 0;
+
+void
+_ecore_exe_init(void)
+{
+ ECORE_EXE_EVENT_ADD = ecore_event_type_new();
+ ECORE_EXE_EVENT_DEL = ecore_event_type_new();
+ ECORE_EXE_EVENT_DATA = ecore_event_type_new();
+ ECORE_EXE_EVENT_ERROR = ecore_event_type_new();
+}
+
+void
+_ecore_exe_shutdown(void)
+{
+ while (exes)
+ ecore_exe_free(exes);
+}
+
+static int run_pri = NORMAL_PRIORITY_CLASS;
+
+EAPI void
+ecore_exe_run_priority_set(int pri)
+{
+ switch (pri)
+ {
+ case ECORE_EXE_WIN32_PRIORITY_IDLE:
+ run_pri = IDLE_PRIORITY_CLASS;
+ break;
+
+ case ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL:
+ run_pri = BELOW_NORMAL_PRIORITY_CLASS;
+ break;
+
+ case ECORE_EXE_WIN32_PRIORITY_NORMAL:
+ run_pri = NORMAL_PRIORITY_CLASS;
+ break;
+
+ case ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL:
+ run_pri = ABOVE_NORMAL_PRIORITY_CLASS;
+ break;
+
+ case ECORE_EXE_WIN32_PRIORITY_HIGH:
+ run_pri = HIGH_PRIORITY_CLASS;
+ break;
+
+ case ECORE_EXE_WIN32_PRIORITY_REALTIME:
+ run_pri = REALTIME_PRIORITY_CLASS;
+ break;
+
+ default:
+ break;
+ }
+}
+
+EAPI int
+ecore_exe_run_priority_get(void)
+{
+ switch (run_pri)
+ {
+ case IDLE_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_IDLE;
+
+ case BELOW_NORMAL_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL;
+
+ case NORMAL_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_NORMAL;
+
+ case ABOVE_NORMAL_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL;
+
+ case HIGH_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_HIGH;
+
+ case REALTIME_PRIORITY_CLASS:
+ return ECORE_EXE_WIN32_PRIORITY_REALTIME;
+
+ /* default should not be reached */
+ default:
+ return ECORE_EXE_WIN32_PRIORITY_NORMAL;
+ }
+}
+
+EAPI Ecore_Exe *
+ecore_exe_run(const char *exe_cmd,
+ const void *data)
+{
+ return ecore_exe_pipe_run(exe_cmd, 0, data);
+}
+
+EAPI Ecore_Exe *
+ecore_exe_pipe_run(const char *exe_cmd,
+ Ecore_Exe_Flags flags,
+ const void *data)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ Ecore_Exe_Event_Add *e;
+ Ecore_Exe *exe;
+ char *ret = NULL;
+
+ exe = calloc(1, sizeof(Ecore_Exe));
+ if (!exe)
+ return NULL;
+
+ if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
+ && (!(flags & ECORE_EXE_PIPE_READ)))
+ /* We need something to auto pipe. */
+ flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
+
+ exe->flags = flags;
+ if (exe->flags & ECORE_EXE_PIPE_READ)
+ if (!_ecore_exe_win32_pipes_set(exe))
+ goto free_exe;
+
+ if (exe->flags & ECORE_EXE_PIPE_WRITE)
+ if (!_ecore_exe_win32_pipes_set(exe))
+ goto close_pipes;
+
+ if (exe->flags & ECORE_EXE_PIPE_ERROR)
+ if (!_ecore_exe_win32_pipes_set(exe))
+ goto close_pipes;
+
+ if ((exe->flags & ECORE_EXE_USE_SH) ||
+ ((ret = strrstr(exe_cmd, ".bat")) && (ret[4] == '\0')))
+ {
+ char buf[PATH_MAX];
+ snprintf(buf, PATH_MAX, "cmd.exe /c %s", exe_cmd);
+ exe->cmd = strdup(buf);
+ }
+ else
+ exe->cmd = strdup(exe_cmd);
+
+ if (!exe->cmd)
+ goto close_pipes;
+
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.hStdOutput = exe->pipe_read.child_pipe_x;
+ si.hStdInput = exe->pipe_write.child_pipe;
+ si.hStdError = exe->pipe_error.child_pipe_x;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ /* FIXME: gerer la priorite */
+
+ if (!CreateProcess(NULL, exe->cmd, NULL, NULL, EINA_TRUE,
+ run_pri | CREATE_SUSPENDED, NULL, NULL, &si, &pi))
+ goto free_exe_cmd;
+
+ /* be sure that the child process is running */
+ /* FIXME: This does not work if the child is an EFL-based app */
+ /* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */
+ /* goto free_exe_cmd; */
+
+ ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
+ exe->process = pi.hProcess;
+ exe->process_thread = pi.hThread;
+ exe->process_id = pi.dwProcessId;
+ exe->thread_id = pi.dwThreadId;
+ exe->data = (void *)data;
+
+ if (!(exe->process2 = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE | SYNCHRONIZE,
+ EINA_FALSE, pi.dwProcessId)))
+ goto close_thread;
+
+ exe->h_close = ecore_main_win32_handler_add(exe->process2, _ecore_exe_close_cb, exe);
+ if (!exe->h_close) goto close_process2;
+
+ if (ResumeThread(exe->process_thread) == ((DWORD)-1))
+ goto close_process2;
+
+ exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
+
+ e = (Ecore_Exe_Event_Add *)calloc(1, sizeof(Ecore_Exe_Event_Add));
+ if (!e) goto delete_h_close;
+
+ e->exe = exe;
+ ecore_event_add(ECORE_EXE_EVENT_ADD, e,
+ _ecore_exe_event_add_free, NULL);
+
+ return exe;
+
+delete_h_close:
+ ecore_main_win32_handler_del(exe->h_close);
+close_process2:
+ CloseHandle(exe->process2);
+close_thread:
+ CloseHandle(exe->process_thread);
+ CloseHandle(exe->process);
+free_exe_cmd:
+ free(exe->cmd);
+close_pipes:
+ _ecore_exe_win32_pipes_close(exe);
+free_exe:
+ free(exe);
+ return NULL;
+}
+
+EAPI void
+ecore_exe_callback_pre_free_set(Ecore_Exe *exe,
+ Ecore_Exe_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
+ "ecore_exe_callback_pre_free_set");
+ return;
+ }
+ exe->pre_free_cb = func;
+}
+
+EAPI Eina_Bool
+ecore_exe_send(Ecore_Exe *exe,
+ const void *data,
+ int size)
+{
+ void *buf;
+
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send");
+ return 0;
+ }
+
+ if (exe->close_stdin)
+ {
+ ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
+ exe, size, data);
+ return 0;
+ }
+
+ if (!exe->pipe_write.child_pipe)
+ {
+ ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! "
+ "Cannot send %d bytes from %p", exe, size, data);
+ return 0;
+ }
+
+ buf = realloc(exe->pipe_write.data_buf, exe->pipe_write.data_size + size);
+ if (!buf) return 0;
+
+ exe->pipe_write.data_buf = buf;
+ memcpy((char *)exe->pipe_write.data_buf + exe->pipe_write.data_size, data, size);
+ exe->pipe_write.data_size += size;
+
+ /* if (exe->pipe_write.) */
+ /* ecore_main_fd_handler_active_set(exe->pipe_write.h, ECORE_FD_WRITE); */
+
+ return 1;
+}
+
+EAPI void
+ecore_exe_close_stdin(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin");
+ return;
+ }
+ exe->close_stdin = 1;
+}
+
+/* Not used on Windows */
+EAPI void
+ecore_exe_auto_limits_set(Ecore_Exe *exe EINA_UNUSED,
+ int start_bytes EINA_UNUSED,
+ int end_bytes EINA_UNUSED,
+ int start_lines EINA_UNUSED,
+ int end_lines EINA_UNUSED)
+{
+}
+
+EAPI Ecore_Exe_Event_Data *
+ecore_exe_event_data_get(Ecore_Exe *exe,
+ Ecore_Exe_Flags flags)
+{
+ Ecore_Exe_Event_Data *e = NULL;
+ unsigned char *inbuf;
+ int inbuf_num;
+
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get");
+ return NULL;
+ }
+
+ /* Sort out what sort of event we are, */
+ /* And get the data. */
+ if (flags & ECORE_EXE_PIPE_READ)
+ {
+ inbuf = exe->pipe_read.data_buf;
+ inbuf_num = exe->pipe_read.data_size;
+ exe->pipe_read.data_buf = NULL;
+ exe->pipe_read.data_size = 0;
+ }
+ else
+ {
+ inbuf = exe->pipe_error.data_buf;
+ inbuf_num = exe->pipe_error.data_size;
+ exe->pipe_error.data_buf = NULL;
+ exe->pipe_error.data_size = 0;
+ }
+
+ e = calloc(1, sizeof(Ecore_Exe_Event_Data));
+ if (e)
+ {
+ e->exe = exe;
+ e->data = inbuf;
+ e->size = inbuf_num;
+ }
+
+ return e;
+}
+
+EAPI void
+ecore_exe_event_data_free(Ecore_Exe_Event_Data *e)
+{
+ if (!e) return;
+ IF_FREE(e->lines);
+ IF_FREE(e->data);
+ free(e);
+}
+
+EAPI void *
+ecore_exe_free(Ecore_Exe *exe)
+{
+ void *data;
+
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free");
+ return NULL;
+ }
+
+ data = exe->data;
+
+ if (exe->pre_free_cb)
+ exe->pre_free_cb(data, exe);
+
+ CloseHandle(exe->process2);
+ CloseHandle(exe->process_thread);
+ CloseHandle(exe->process);
+ free(exe->cmd);
+ _ecore_exe_win32_pipes_close(exe);
+ exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
+ ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE);
+ if (exe->tag) free(exe->tag);
+ free(exe);
+
+ return data;
+}
+
+EAPI pid_t
+ecore_exe_pid_get(const Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get");
+ return -1;
+ }
+ return exe->process_id;
+}
+
+EAPI void
+ecore_exe_tag_set(Ecore_Exe *exe,
+ const char *tag)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set");
+ return;
+ }
+ IF_FREE(exe->tag);
+ if (tag)
+ exe->tag = strdup(tag);
+}
+
+EAPI const char *
+ecore_exe_tag_get(const Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get");
+ return NULL;
+ }
+ return exe->tag;
+}
+
+EAPI const char *
+ecore_exe_cmd_get(const Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get");
+ return NULL;
+ }
+ return exe->cmd;
+}
+
+EAPI void *
+ecore_exe_data_get(const Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+ return NULL;
+ }
+ return exe->data;
+}
+
+EAPI Ecore_Exe_Flags
+ecore_exe_flags_get(const Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+ return 0;
+ }
+ return exe->flags;
+}
+
+EAPI void
+ecore_exe_pause(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause");
+ return;
+ }
+
+ if (exe->is_suspended)
+ return;
+
+ if (SuspendThread(exe->process_thread) != (DWORD)-1)
+ exe->is_suspended = 1;
+}
+
+EAPI void
+ecore_exe_continue(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue");
+ return;
+ }
+
+ if (!exe->is_suspended)
+ return;
+
+ if (ResumeThread(exe->process_thread) != (DWORD)-1)
+ exe->is_suspended = 0;
+}
+
+EAPI void
+ecore_exe_interrupt(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt");
+ return;
+ }
+
+ CloseHandle(exe->process_thread);
+ CloseHandle(exe->process);
+ exe->sig = ECORE_EXE_WIN32_SIGINT;
+ while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ;
+}
+
+EAPI void
+ecore_exe_quit(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit");
+ return;
+ }
+
+ CloseHandle(exe->process_thread);
+ CloseHandle(exe->process);
+ exe->sig = ECORE_EXE_WIN32_SIGQUIT;
+ while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ;
+}
+
+EAPI void
+ecore_exe_terminate(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate");
+ return;
+ }
+
+/* CloseHandle(exe->thread); */
+ CloseHandle(exe->process);
+ exe->sig = ECORE_EXE_WIN32_SIGTERM;
+ while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ;
+}
+
+EAPI void
+ecore_exe_kill(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill");
+ return;
+ }
+
+ CloseHandle(exe->process_thread);
+ CloseHandle(exe->process);
+ exe->sig = ECORE_EXE_WIN32_SIGKILL;
+ while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ;
+}
+
+EAPI void
+ecore_exe_signal(Ecore_Exe *exe,
+ int num EINA_UNUSED)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal");
+ return;
+ }
+
+ /* does nothing */
+}
+
+EAPI void
+ecore_exe_hup(Ecore_Exe *exe)
+{
+ if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+ {
+ ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup");
+ return;
+ }
+
+ /* does nothing */
+}
+
+/* FIXME: manage error mode */
+static int
+_ecore_exe_win32_pipe_thread_generic_cb(void *data,
+ Ecore_Exe_Flags flags)
+{
+#define BUFSIZE 2048
+ char buf[BUFSIZE];
+ Ecore_Exe *exe;
+ char *current_buf = NULL;
+ HANDLE child_pipe;
+ Ecore_Pipe *ecore_pipe;
+ Ecore_Exe_Event_Data *event;
+ DWORD size;
+ DWORD current_size = 0;
+ BOOL res;
+
+ exe = (Ecore_Exe *)data;
+
+ /* Sort out what sort of handler we are. */
+ /* And get any left over data from last time. */
+ if ((exe->flags & ECORE_EXE_PIPE_READ) && (flags == ECORE_EXE_PIPE_READ))
+ {
+ child_pipe = exe->pipe_read.child_pipe;
+ ecore_pipe = exe->pipe_read.p;
+ flags = ECORE_EXE_PIPE_READ;
+ }
+ else if ((exe->flags & ECORE_EXE_PIPE_ERROR) && (flags == ECORE_EXE_PIPE_ERROR))
+ {
+ child_pipe = exe->pipe_error.child_pipe;
+ ecore_pipe = exe->pipe_error.p;
+ flags = ECORE_EXE_PIPE_ERROR;
+ }
+ else
+ return 0;
+
+ while (1)
+ {
+ if (!PeekNamedPipe(child_pipe, buf, sizeof(buf), &size, &current_size, NULL))
+ continue;
+ if (size == 0)
+ continue;
+ current_buf = (char *)malloc(current_size);
+ if (!current_buf)
+ continue;
+ res = ReadFile(child_pipe, current_buf, current_size, &size, NULL);
+ if (!res || (size == 0))
+ {
+ free(current_buf);
+ current_buf = NULL;
+ continue;
+ }
+ if (current_size != size)
+ {
+ free(current_buf);
+ current_buf = NULL;
+ continue;
+ }
+ current_size = size;
+
+ if (flags == ECORE_EXE_PIPE_READ)
+ {
+ exe->pipe_read.data_buf = current_buf;
+ exe->pipe_read.data_size = current_size;
+ }
+ else
+ {
+ exe->pipe_error.data_buf = current_buf;
+ exe->pipe_error.data_size = current_size;
+ }
+
+ event = ecore_exe_event_data_get(exe, flags);
+ if (event)
+ ecore_pipe_write(ecore_pipe, &event, sizeof(event));
+
+ current_buf = NULL;
+ current_size = 0;
+ }
+
+ return 1;
+}
+
+static DWORD WINAPI
+_ecore_exe_win32_pipe_thread_read_cb(void *data)
+{
+ return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_READ);
+}
+
+static DWORD WINAPI
+_ecore_exe_win32_pipe_thread_error_cb(void *data)
+{
+ return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_ERROR);
+}
+
+static int
+_ecore_exe_win32_pipes_set(Ecore_Exe *exe)
+{
+ SECURITY_ATTRIBUTES sa;
+ HANDLE child_pipe;
+ HANDLE child_pipe_x;
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = EINA_TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&child_pipe, &child_pipe_x, &sa, 0))
+ return 0;
+ if (exe->flags & ECORE_EXE_PIPE_WRITE)
+ {
+ if (!SetHandleInformation(child_pipe_x, HANDLE_FLAG_INHERIT, 0))
+ goto close_pipe;
+ }
+ else
+ {
+ if (!SetHandleInformation(child_pipe, HANDLE_FLAG_INHERIT, 0))
+ goto close_pipe;
+ }
+
+ if (exe->flags & ECORE_EXE_PIPE_READ)
+ {
+ exe->pipe_read.child_pipe = child_pipe;
+ exe->pipe_read.child_pipe_x = child_pipe_x;
+ exe->pipe_read.p = ecore_pipe_add(_ecore_exe_pipe_read_cb, exe);
+ exe->pipe_read.thread = CreateThread(NULL, 0,
+ _ecore_exe_win32_pipe_thread_read_cb,
+ exe, 0, NULL);
+ }
+ else if (exe->flags & ECORE_EXE_PIPE_WRITE)
+ {
+ exe->pipe_write.child_pipe = child_pipe;
+ exe->pipe_write.child_pipe_x = child_pipe_x;
+/* exe->pipe_write.thread = CreateThread(NULL, 0, */
+/* _ecore_exe_win32_pipe_thread_cb, */
+/* exe, 0, NULL); */
+ }
+ else
+ {
+ exe->pipe_error.child_pipe = child_pipe;
+ exe->pipe_error.child_pipe_x = child_pipe_x;
+ exe->pipe_error.p = ecore_pipe_add(_ecore_exe_pipe_error_cb, exe);
+ exe->pipe_error.thread = CreateThread(NULL, 0,
+ _ecore_exe_win32_pipe_thread_error_cb,
+ exe, 0, NULL);
+ }
+
+ return 1;
+
+close_pipe:
+ CloseHandle(child_pipe);
+ CloseHandle(child_pipe_x);
+
+ return 0;
+}
+
+static void
+_ecore_exe_win32_pipes_close(Ecore_Exe *exe)
+{
+ if (exe->flags & ECORE_EXE_PIPE_READ)
+ {
+ if (exe->pipe_read.child_pipe)
+ {
+ CloseHandle(exe->pipe_read.child_pipe);
+ exe->pipe_read.child_pipe = NULL;
+ }
+ if (exe->pipe_read.child_pipe_x)
+ {
+ CloseHandle(exe->pipe_read.child_pipe_x);
+ exe->pipe_read.child_pipe_x = NULL;
+ }
+ }
+
+ if (exe->flags & ECORE_EXE_PIPE_WRITE)
+ {
+ if (exe->pipe_write.child_pipe)
+ {
+ CloseHandle(exe->pipe_write.child_pipe);
+ exe->pipe_write.child_pipe = NULL;
+ }
+ if (exe->pipe_write.child_pipe_x)
+ {
+ CloseHandle(exe->pipe_write.child_pipe_x);
+ exe->pipe_write.child_pipe_x = NULL;
+ }
+ }
+
+ if (exe->flags & ECORE_EXE_PIPE_ERROR)
+ {
+ if (exe->pipe_error.child_pipe)
+ {
+ CloseHandle(exe->pipe_error.child_pipe);
+ exe->pipe_error.child_pipe = NULL;
+ }
+ if (exe->pipe_error.child_pipe_x)
+ {
+ CloseHandle(exe->pipe_error.child_pipe_x);
+ exe->pipe_error.child_pipe_x = NULL;
+ }
+ }
+}
+
+static DWORD WINAPI
+_ecore_exe_thread_procedure(LPVOID data EINA_UNUSED)
+{
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
+ return 1;
+}
+
+static BOOL CALLBACK
+_ecore_exe_enum_windows_procedure(HWND window,
+ LPARAM data)
+{
+ Ecore_Exe *exe;
+ DWORD thread_id;
+
+ exe = (Ecore_Exe *)data;
+ thread_id = GetWindowThreadProcessId(window, NULL);
+
+ if (thread_id == exe->thread_id)
+ {
+ /* Ctrl-C or Ctrl-Break */
+ if (CreateRemoteThread(exe->process, NULL, 0,
+ (LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL,
+ 0, NULL))
+ {
+ printf ("remote thread\n");
+ return EINA_FALSE;
+ }
+
+ if ((exe->sig == ECORE_EXE_WIN32_SIGINT) ||
+ (exe->sig == ECORE_EXE_WIN32_SIGQUIT))
+ {
+ printf ("int or quit\n");
+ return EINA_FALSE;
+ }
+
+ /* WM_CLOSE message */
+ PostMessage(window, WM_CLOSE, 0, 0);
+ if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
+ {
+ printf ("CLOSE\n");
+ return EINA_FALSE;
+ }
+
+ /* WM_QUIT message */
+ PostMessage(window, WM_QUIT, 0, 0);
+ if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0)
+ {
+ printf ("QUIT\n");
+ return EINA_FALSE;
+ }
+
+ /* Exit process */
+ if (CreateRemoteThread(exe->process, NULL, 0,
+ (LPTHREAD_START_ROUTINE)ExitProcess, NULL,
+ 0, NULL))
+ {
+ printf ("remote thread 2\n");
+ return EINA_FALSE;
+ }
+
+ if (exe->sig == ECORE_EXE_WIN32_SIGTERM)
+ {
+ printf ("term\n");
+ return EINA_FALSE;
+ }
+
+ TerminateProcess(exe->process, 0);
+
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_exe_event_add_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Add *e;
+
+ e = (Ecore_Exe_Event_Add *)ev;
+ free(e);
+}
+
+static void
+_ecore_exe_event_del_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Del *e;
+
+ e = (Ecore_Exe_Event_Del *)ev;
+ if (e->exe)
+ ecore_exe_free(e->exe);
+ free(e);
+}
+
+static void
+_ecore_exe_event_exe_data_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Exe_Event_Data *e;
+
+ e = (Ecore_Exe_Event_Data *)ev;
+ ecore_exe_event_data_free(e);
+}
+
+static Eina_Bool
+_ecore_exe_close_cb(void *data,
+ Ecore_Win32_Handler *wh EINA_UNUSED)
+{
+ Ecore_Exe_Event_Del *e;
+ Ecore_Exe *exe;
+ DWORD exit_code = 0;
+
+ e = calloc(1, sizeof(Ecore_Exe_Event_Del));
+ if (!e) return 0;
+
+ exe = (Ecore_Exe *)data;
+
+ if (GetExitCodeProcess(exe->process2, &exit_code))
+ {
+ e->exit_code = exit_code;
+ e->exited = 1;
+ }
+ else
+ {
+ char *msg;
+
+ msg = evil_last_error_get();
+ printf("%s\n", msg);
+ free(msg);
+ }
+ e->pid = exe->process_id;
+ e->exe = exe;
+
+ ecore_event_add(ECORE_EXE_EVENT_DEL, e,
+ _ecore_exe_event_del_free, NULL);
+
+ return 0;
+}
+
+static void
+_ecore_exe_pipe_read_cb(void *data,
+ void *buf,
+ unsigned int size)
+{
+ Ecore_Exe_Event_Data *e;
+
+ e = *((Ecore_Exe_Event_Data **)buf);
+ if (e)
+ ecore_event_add(ECORE_EXE_EVENT_DATA, e,
+ _ecore_exe_event_exe_data_free,
+ NULL);
+}
+
+static int
+_ecore_exe_pipe_write_cb(void *data,
+ Ecore_Win32_Handler *wh EINA_UNUSED)
+{
+ char buf[READBUFSIZ];
+ Ecore_Exe *exe;
+ DWORD num_exe;
+ BOOL res;
+
+ exe = (Ecore_Exe *)data;
+
+ res = WriteFile(exe->pipe_write.child_pipe_x, buf, READBUFSIZ, &num_exe, NULL);
+ if (!res || num_exe == 0)
+ {
+ /* FIXME: what to do here ?? */
+ }
+
+ if (exe->close_stdin == 1)
+ {
+ if (exe->pipe_write.h)
+ {
+ ecore_main_win32_handler_del(exe->pipe_write.h);
+ exe->pipe_write.h = NULL;
+ }
+ exe->pipe_write.h = NULL;
+ CloseHandle(exe->pipe_write.child_pipe);
+ exe->pipe_write.child_pipe = NULL;
+ }
+
+ return 1;
+}
+
+static void
+_ecore_exe_pipe_error_cb(void *data,
+ void *buf,
+ unsigned int size)
+{
+ Ecore_Exe_Event_Data *e;
+
+ e = *((Ecore_Exe_Event_Data **)buf);
+ if (e)
+ ecore_event_add(ECORE_EXE_EVENT_ERROR, e,
+ _ecore_exe_event_exe_data_free,
+ NULL);
+}
+
diff --git a/src/lib/ecore/ecore_exe_wince.c b/src/lib/ecore/ecore_exe_wince.c
new file mode 100644
index 0000000000..c07fcbe31b
--- /dev/null
+++ b/src/lib/ecore/ecore_exe_wince.c
@@ -0,0 +1,21 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+void
+_ecore_exe_init(void)
+{
+}
+
+void
+_ecore_exe_shutdown(void)
+{
+}
+
diff --git a/src/lib/ecore/ecore_getopt.c b/src/lib/ecore/ecore_getopt.c
new file mode 100644
index 0000000000..42e43e8915
--- /dev/null
+++ b/src/lib/ecore/ecore_getopt.c
@@ -0,0 +1,1936 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+#else
+# define gettext(x) (x)
+# define dgettext(domain, x) (x)
+#endif
+
+#define _(x) dgettext("ecore", x)
+
+#ifdef _WIN32_WCE
+# include <Evil.h>
+#endif
+
+#ifdef HAVE_EXOTIC
+# include <Exotic.h>
+#endif
+
+#include "Ecore.h"
+#include "Ecore_Getopt.h"
+
+static const char *prog = NULL;
+static char **_argv = NULL;
+static int _argc = 0;
+static int cols = 80;
+static int helpcol = 80 / 3;
+
+static void
+_ecore_getopt_help_print_replace_program(FILE *fp,
+ const Ecore_Getopt *parser EINA_UNUSED,
+ const char *text)
+{
+ do
+ {
+ const char *d = strchr(text, '%');
+
+ if (!d)
+ {
+ fputs(text, fp);
+ break;
+ }
+
+ if (fwrite(text, 1, d - text, fp) != (size_t)(d - text))
+ return;
+ d++;
+ if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
+ {
+ fputs(prog ? prog : "???", fp);
+ d += sizeof("prog") - 1;
+ }
+ else
+ {
+ if (d[0] == '%')
+ d++;
+ fputc('%', fp);
+ }
+
+ text = d;
+ }
+ while (text[0] != '\0');
+
+ fputc('\n', fp);
+}
+
+static void
+_ecore_getopt_version(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ fputs(_("Version:"), fp);
+ fputc(' ', fp);
+ _ecore_getopt_help_print_replace_program(fp, parser, parser->version);
+}
+
+static void
+_ecore_getopt_help_usage(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ fputs(_("Usage:"), fp);
+ fputc(' ', fp);
+
+ if (!parser->usage)
+ {
+ fprintf(fp, _("%s [options]\n"), prog);
+ return;
+ }
+
+ _ecore_getopt_help_print_replace_program(fp, parser, gettext(parser->usage));
+}
+
+static int
+_ecore_getopt_help_line(FILE *fp,
+ const int base,
+ const int total,
+ int used,
+ const char *text,
+ int len)
+{
+ int linebreak = 0;
+ do
+ {
+ /* process line considering spaces (new line and tabs are spaces!) */
+ while ((used < total) && (len > 0))
+ {
+ const char *space = NULL;
+ int i, todo;
+
+ todo = total - used;
+ if (todo > len)
+ todo = len;
+
+ for (i = 0; i < todo; i++)
+ if (isspace((unsigned char)text[i]))
+ {
+ space = text + i;
+ break;
+ }
+
+ if (space)
+ {
+ i = fwrite(text, 1, i, fp);
+ i++;
+ text += i;
+ len -= i;
+ used += i;
+
+ if (linebreak)
+ {
+ linebreak = 0;
+ continue;
+ }
+
+ if (space[0] == '\n')
+ break;
+ else if (space[0] == '\t')
+ {
+ int c;
+
+ used--;
+ c = ((used / 8) + 1) * 8;
+ if (c < total)
+ {
+ for (; used < c; used++)
+ fputc(' ', fp);
+ }
+ else
+ {
+ text--;
+ len++;
+ break;
+ }
+ }
+ else if (used < total)
+ fputc(space[0], fp);
+ }
+ else
+ {
+ i = fwrite(text, 1, i, fp);
+ text += i;
+ len -= i;
+ used += i;
+ }
+ linebreak = 0;
+ }
+ if (len <= 0)
+ break;
+ linebreak = 1;
+ fputc('\n', fp);
+ for (used = 0; used < base; used++)
+ fputc(' ', fp);
+ }
+ while (1);
+
+ return used;
+}
+
+static void
+_ecore_getopt_help_description(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ const char *p, *prg, *ver;
+ int used, prglen, verlen;
+
+ p = gettext(parser->description);
+ if (!p)
+ return;
+
+ fputc('\n', fp);
+
+ prg = prog ? prog : "???";
+ ver = parser->version ? parser->version : "???";
+
+ prglen = strlen(prg);
+ verlen = strlen(ver);
+
+ used = 0;
+
+ do
+ {
+ const char *d = strchr(p, '%');
+
+ if (!d)
+ {
+ _ecore_getopt_help_line(fp, 0, cols, used, p, strlen(p));
+ break;
+ }
+
+ used = _ecore_getopt_help_line(fp, 0, cols, used, p, d - p);
+ d++;
+ if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
+ {
+ used = _ecore_getopt_help_line(fp, 0, cols, used, prg, prglen);
+ d += sizeof("prog") - 1;
+ }
+ else if (strncmp(d, "version", sizeof("version") - 1) == 0)
+ {
+ used = _ecore_getopt_help_line(fp, 0, cols, used, ver, verlen);
+ d += sizeof("version") - 1;
+ }
+ else
+ {
+ if (d[0] == '%')
+ d++;
+ used = _ecore_getopt_help_line(fp, 0, cols, used, "%", 1);
+ }
+
+ p = d;
+ }
+ while (p[0] != '\0');
+
+ fputs("\n\n", fp);
+}
+
+static void
+_ecore_getopt_copyright(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ const char *txt = gettext(parser->copyright);
+ fputs(_("Copyright:"), fp);
+ fputs("\n ", fp);
+ _ecore_getopt_help_line
+ (fp, 3, cols, 3, txt, strlen(txt));
+ fputc('\n', fp);
+}
+
+static void
+_ecore_getopt_license(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ const char *txt = gettext(parser->license);
+ fputs(_("License:"), fp);
+ fputs("\n ", fp);
+ _ecore_getopt_help_line
+ (fp, 3, cols, 3, txt, strlen(txt));
+ fputc('\n', fp);
+}
+
+static Ecore_Getopt_Desc_Arg_Requirement
+_ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc)
+{
+ switch (desc->action)
+ {
+ case ECORE_GETOPT_ACTION_STORE:
+ return desc->action_param.store.arg_req;
+
+ case ECORE_GETOPT_ACTION_STORE_CONST:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ case ECORE_GETOPT_ACTION_STORE_TRUE:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ case ECORE_GETOPT_ACTION_STORE_FALSE:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ case ECORE_GETOPT_ACTION_CHOICE:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
+
+ case ECORE_GETOPT_ACTION_APPEND:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
+
+ case ECORE_GETOPT_ACTION_COUNT:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ case ECORE_GETOPT_ACTION_CALLBACK:
+ return desc->action_param.callback.arg_req;
+
+ case ECORE_GETOPT_ACTION_HELP:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ case ECORE_GETOPT_ACTION_VERSION:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+
+ default:
+ return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+ }
+}
+
+static void
+_ecore_getopt_help_desc_setup_metavar(const Ecore_Getopt_Desc *desc,
+ char *metavar,
+ int *metavarlen,
+ int maxsize)
+{
+ if (desc->metavar)
+ {
+ const char *txt = gettext(desc->metavar);
+ *metavarlen = strlen(txt);
+ if (*metavarlen > maxsize - 1)
+ *metavarlen = maxsize - 1;
+
+ memcpy(metavar, txt, *metavarlen);
+ metavar[*metavarlen] = '\0';
+ }
+ else if (desc->longname)
+ {
+ int i;
+
+ *metavarlen = strlen(desc->longname);
+ if (*metavarlen > maxsize - 1)
+ *metavarlen = maxsize - 1;
+
+ for (i = 0; i < *metavarlen; i++)
+ metavar[i] = toupper((int) desc->longname[i]);
+ metavar[i] = '\0';
+ }
+}
+
+static int
+_ecore_getopt_help_desc_show_arg(FILE *fp,
+ Ecore_Getopt_Desc_Arg_Requirement requirement,
+ const char *metavar,
+ int metavarlen)
+{
+ int used;
+
+ if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ return 0;
+
+ used = 0;
+
+ if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
+ {
+ fputc('[', fp);
+ used++;
+ }
+
+ if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ {
+ fputc('=', fp);
+ fputs(metavar, fp);
+ used += metavarlen + 1;
+ }
+
+ if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
+ {
+ fputc(']', fp);
+ used++;
+ }
+
+ return used;
+}
+
+static int
+_ecore_getopt_help_desc_store(FILE *fp,
+ const int base,
+ const int total,
+ int used,
+ const Ecore_Getopt_Desc *desc)
+{
+ const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
+ char buf[64];
+ const char *str;
+ size_t len;
+
+ fputc('\n', fp);
+ for (used = 0; used < base; used++)
+ fputc(' ', fp);
+
+ switch (store->type)
+ {
+ case ECORE_GETOPT_TYPE_STR:
+ str = "STR";
+ len = sizeof("STR") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_BOOL:
+ str = "BOOL";
+ len = sizeof("BOOL") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_SHORT:
+ str = "SHORT";
+ len = sizeof("SHORT") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_INT:
+ str = "INT";
+ len = sizeof("INT") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_LONG:
+ str = "LONG";
+ len = sizeof("LONG") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_USHORT:
+ str = "USHORT";
+ len = sizeof("USHORT") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_UINT:
+ str = "UINT";
+ len = sizeof("UINT") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_ULONG:
+ str = "ULONG";
+ len = sizeof("ULONG") - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_DOUBLE:
+ str = "DOUBLE";
+ len = sizeof("DOUBLE") - 1;
+ break;
+
+ default:
+ str = "???";
+ len = sizeof("???") - 1;
+ }
+
+ used = _ecore_getopt_help_line
+ (fp, base, total, used, _("Type: "), strlen(_("Type: ")));
+ used = _ecore_getopt_help_line(fp, base, total, used, str, len);
+
+ if (store->arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
+ goto end;
+
+ used = _ecore_getopt_help_line
+ (fp, base, total, used, ". ", sizeof(". ") - 1);
+
+ switch (store->type)
+ {
+ case ECORE_GETOPT_TYPE_STR:
+ str = store->def.strv;
+ len = str ? strlen(str) : 0;
+ break;
+
+ case ECORE_GETOPT_TYPE_BOOL:
+ str = store->def.boolv ? "true" : "false";
+ len = strlen(str);
+ break;
+
+ case ECORE_GETOPT_TYPE_SHORT:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%hd", store->def.shortv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_INT:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%d", store->def.intv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_LONG:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%ld", store->def.longv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_USHORT:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%hu", store->def.ushortv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_UINT:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%u", store->def.uintv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_ULONG:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%lu", store->def.ulongv);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ case ECORE_GETOPT_TYPE_DOUBLE:
+ str = buf;
+ len = snprintf(buf, sizeof(buf), "%f", store->def.doublev);
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+ break;
+
+ default:
+ str = "???";
+ len = sizeof("???") - 1;
+ }
+
+ used = _ecore_getopt_help_line
+ (fp, base, total, used, _("Default: "), strlen(_("Default: ")));
+ used = _ecore_getopt_help_line(fp, base, total, used, str, len);
+
+end:
+ return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
+}
+
+static int
+_ecore_getopt_help_desc_choices(FILE *fp,
+ const int base,
+ const int total,
+ int used,
+ const Ecore_Getopt_Desc *desc)
+{
+ const char *const *itr;
+ const char sep[] = ", ";
+ const int seplen = sizeof(sep) - 1;
+
+ if (used > 0)
+ {
+ fputc('\n', fp);
+ used = 0;
+ }
+ for (; used < base; used++)
+ fputc(' ', fp);
+
+ used = _ecore_getopt_help_line
+ (fp, base, total, used, _("Choices: "), strlen(_("Choices: ")));
+
+ for (itr = desc->action_param.choices; *itr; itr++)
+ {
+ used = _ecore_getopt_help_line
+ (fp, base, total, used, *itr, strlen(*itr));
+ if (itr[1])
+ used = _ecore_getopt_help_line(fp, base, total, used, sep, seplen);
+ }
+
+ return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
+}
+
+static void
+_ecore_getopt_help_desc(FILE *fp,
+ const Ecore_Getopt_Desc *desc)
+{
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ char metavar[32] = "ARG";
+ int metavarlen = 3;
+ int used;
+
+ arg_req = _ecore_getopt_desc_arg_requirement(desc);
+ if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ _ecore_getopt_help_desc_setup_metavar
+ (desc, metavar, &metavarlen, sizeof(metavar));
+
+ fputs(" ", fp);
+ used = 2;
+
+ if (desc->shortname)
+ {
+ fputc('-', fp);
+ fputc(desc->shortname, fp);
+ used += 2;
+ used += _ecore_getopt_help_desc_show_arg
+ (fp, arg_req, metavar, metavarlen);
+ }
+
+ if (desc->shortname && desc->longname)
+ {
+ fputs(", ", fp);
+ used += 2;
+ }
+
+ if (desc->longname)
+ {
+ int namelen = strlen(desc->longname);
+
+ fputs("--", fp);
+ fputs(desc->longname, fp);
+ used += 2 + namelen;
+ used += _ecore_getopt_help_desc_show_arg
+ (fp, arg_req, metavar, metavarlen);
+ }
+
+ if (!desc->help)
+ goto end;
+
+ if (used + 3 >= helpcol)
+ {
+ fputc('\n', fp);
+ used = 0;
+ }
+
+ for (; used < helpcol; used++)
+ fputc(' ', fp);
+
+ used = _ecore_getopt_help_line
+ (fp, helpcol, cols, used, desc->help, strlen(desc->help));
+
+ switch (desc->action)
+ {
+ case ECORE_GETOPT_ACTION_STORE:
+ _ecore_getopt_help_desc_store(fp, helpcol, cols, used, desc);
+ break;
+
+ case ECORE_GETOPT_ACTION_CHOICE:
+ _ecore_getopt_help_desc_choices(fp, helpcol, cols, used, desc);
+ break;
+
+ default:
+ break;
+ }
+
+end:
+ fputc('\n', fp);
+}
+
+static Eina_Bool
+_ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc)
+{
+ return (desc->shortname == '\0') && (!desc->longname);
+}
+
+static void
+_ecore_getopt_help_options(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ const Ecore_Getopt_Desc *desc;
+
+ fputs(_("Options:\n"), fp);
+
+ for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ _ecore_getopt_help_desc(fp, desc);
+
+ fputc('\n', fp);
+}
+
+/**
+ * Show nicely formatted help message for the given parser.
+ *
+ * @param fp The file the message will be printed on.
+ * @param parser The parser to be used.
+ */
+EAPI void
+ecore_getopt_help(FILE *fp,
+ const Ecore_Getopt *parser)
+{
+ const char *var;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (!parser) return;
+
+ if (_argc < 1)
+ {
+ ecore_app_args_get(&_argc, &_argv);
+ if ((_argc > 0) && (_argv[0]))
+ prog = _argv[0];
+ else
+ prog = parser->prog;
+ }
+
+ var = getenv("COLUMNS");
+ if (var)
+ {
+ cols = atoi(var);
+ if (cols < 20)
+ cols = 20;
+
+ helpcol = cols / 3;
+ }
+
+ _ecore_getopt_help_usage(fp, parser);
+ _ecore_getopt_help_description(fp, parser);
+ _ecore_getopt_help_options(fp, parser);
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_long(const Ecore_Getopt *parser,
+ const char *name)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ const char *p = strchr(name, '=');
+ int len = 0;
+
+ if (p)
+ len = p - name;
+
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ {
+ if (!desc->longname)
+ continue;
+
+ if (p)
+ {
+ if ((strncmp(name, desc->longname, len) == 0) &&
+ (desc->longname[len] == '\0'))
+ return desc;
+ }
+ else
+ {
+ if (strcmp(name, desc->longname) == 0)
+ return desc;
+ }
+ }
+
+ return NULL;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_short(const Ecore_Getopt *parser,
+ char name)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ if (name == desc->shortname)
+ return desc;
+ return NULL;
+}
+
+static int
+_ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser,
+ int argc,
+ char **argv)
+{
+ char **nonargs;
+ int src, dst, used, base;
+
+ nonargs = alloca(sizeof(char *) * argc);
+ src = 1;
+ dst = 1;
+ used = 0;
+ base = 0;
+ while (src < argc)
+ {
+ const Ecore_Getopt_Desc *desc;
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ char *arg = argv[src];
+
+ if (arg[0] != '-')
+ goto found_nonarg;
+
+ if (arg[1] == '-')
+ {
+ if (arg[2] == '\0') /* explicit end of options, "--" */
+ {
+ base = 1;
+ break;
+ }
+ desc = _ecore_getopt_parse_find_long(parser, arg + 2);
+ }
+ else
+ desc = _ecore_getopt_parse_find_short(parser, arg[1]);
+
+ if (!desc)
+ {
+ if (arg[1] == '-')
+ fprintf(stderr, _("ERROR: unknown option --%s.\n"), arg + 2);
+ else
+ fprintf(stderr, _("ERROR: unknown option -%c.\n"), arg[1]);
+ if (parser->strict)
+ {
+ memmove(argv + dst, nonargs, used * sizeof(char *));
+ return -1;
+ }
+ else
+ goto found_nonarg;
+ }
+
+ if (src != dst)
+ argv[dst] = argv[src];
+ src++;
+ dst++;
+
+ arg_req = _ecore_getopt_desc_arg_requirement(desc);
+ if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ continue;
+
+ if (strchr(arg, '='))
+ continue;
+
+ if ((src >= argc) || (argv[src][0] == '-'))
+ continue;
+
+ if (src != dst)
+ argv[dst] = argv[src];
+ src++;
+ dst++;
+ continue;
+
+found_nonarg:
+ nonargs[used] = arg;
+ used++;
+ src++;
+ }
+
+ if (!base) /* '--' not found */
+ base = dst;
+ else
+ {
+ base = dst;
+ if (src != dst)
+ argv[dst] = argv[src];
+ dst++;
+ }
+
+ memmove(argv + dst, nonargs, used * sizeof(char *));
+ return base;
+}
+
+static void
+_ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc,
+ const char *fmt,
+ ...)
+{
+ va_list ap;
+
+ fputs(_("ERROR: "), stderr);
+
+ if (desc->shortname)
+ {
+ fputc('-', stderr);
+ fputc(desc->shortname, stderr);
+ }
+
+ if (desc->shortname && desc->longname)
+ fputs(", ", stderr);
+
+ if (desc->longname)
+ {
+ fputs("--", stderr);
+ fputs(desc->longname, stderr);
+ }
+
+ fputs(": ", stderr);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static Eina_Bool
+_ecore_getopt_parse_bool(const char *str,
+ Eina_Bool *v)
+{
+ if ((strcmp(str, "0") == 0) ||
+ (strcasecmp(str, "f") == 0) ||
+ (strcasecmp(str, "false") == 0) ||
+ (strcasecmp(str, "no") == 0) ||
+ (strcasecmp(str, "off") == 0)
+ )
+ {
+ *v = EINA_FALSE;
+ return EINA_TRUE;
+ }
+ else if ((strcmp(str, "1") == 0) ||
+ (strcasecmp(str, "t") == 0) ||
+ (strcasecmp(str, "true") == 0) ||
+ (strcasecmp(str, "yes") == 0) ||
+ (strcasecmp(str, "on") == 0)
+ )
+ {
+ *v = EINA_TRUE;
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_long(const char *str,
+ long int *v)
+{
+ char *endptr = NULL;
+ *v = strtol(str, &endptr, 0);
+ return endptr > str;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_double(const char *str,
+ double *v)
+{
+ char *endptr = NULL;
+ *v = strtod(str, &endptr);
+ return endptr > str;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_store(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *value,
+ const char *arg_val)
+{
+ const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
+ long int v;
+ double d;
+ Eina_Bool b;
+
+ if (!value->ptrp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+
+ switch (store->arg_req)
+ {
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
+ goto use_optional;
+
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
+ if (!arg_val)
+ goto use_optional;
+
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
+ break;
+ }
+
+ switch (store->type)
+ {
+ case ECORE_GETOPT_TYPE_STR:
+ *value->strp = (char *)arg_val;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_BOOL:
+ if (_ecore_getopt_parse_bool(arg_val, &b))
+ {
+ *value->boolp = b;
+ return EINA_TRUE;
+ }
+ else
+ {
+ _ecore_getopt_desc_print_error
+ (desc, _("unknown boolean value %s.\n"), arg_val);
+ return EINA_FALSE;
+ }
+
+ case ECORE_GETOPT_TYPE_SHORT:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->shortp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_INT:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->intp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_LONG:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->longp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_USHORT:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->ushortp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_UINT:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->uintp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_ULONG:
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ *value->ulongp = v;
+ return EINA_TRUE;
+
+ case ECORE_GETOPT_TYPE_DOUBLE:
+ if (!_ecore_getopt_parse_double(arg_val, &d))
+ goto error;
+ *value->doublep = d;
+ break;
+ }
+
+ return EINA_TRUE;
+
+error:
+ _ecore_getopt_desc_print_error
+ (desc, _("invalid number format %s\n"), arg_val);
+ return EINA_FALSE;
+
+use_optional:
+ switch (store->type)
+ {
+ case ECORE_GETOPT_TYPE_STR:
+ *value->strp = (char *)store->def.strv;
+ break;
+
+ case ECORE_GETOPT_TYPE_BOOL:
+ *value->boolp = store->def.boolv;
+ break;
+
+ case ECORE_GETOPT_TYPE_SHORT:
+ *value->shortp = store->def.shortv;
+ break;
+
+ case ECORE_GETOPT_TYPE_INT:
+ *value->intp = store->def.intv;
+ break;
+
+ case ECORE_GETOPT_TYPE_LONG:
+ *value->longp = store->def.longv;
+ break;
+
+ case ECORE_GETOPT_TYPE_USHORT:
+ *value->ushortp = store->def.ushortv;
+ break;
+
+ case ECORE_GETOPT_TYPE_UINT:
+ *value->uintp = store->def.uintv;
+ break;
+
+ case ECORE_GETOPT_TYPE_ULONG:
+ *value->ulongp = store->def.ulongv;
+ break;
+
+ case ECORE_GETOPT_TYPE_DOUBLE:
+ *value->doublep = store->def.doublev;
+ break;
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_store_const(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (!val->ptrp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+
+ *val->ptrp = (void *)desc->action_param.store_const;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_store_true(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (!val->boolp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+ *val->boolp = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_store_false(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (!val->boolp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+ *val->boolp = EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_choice(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val)
+{
+ const char *const *pchoice;
+
+ if (!val->strp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+
+ pchoice = desc->action_param.choices;
+ for (; *pchoice; pchoice++)
+ if (strcmp(*pchoice, arg_val) == 0)
+ {
+ *val->strp = (char *)*pchoice;
+ return EINA_TRUE;
+ }
+
+ _ecore_getopt_desc_print_error
+ (desc, _("invalid choice \"%s\". Valid values are: "), arg_val);
+
+ pchoice = desc->action_param.choices;
+ for (; *pchoice; pchoice++)
+ {
+ fputs(*pchoice, stderr);
+ if (pchoice[1])
+ fputs(", ", stderr);
+ }
+
+ fputs(".\n", stderr);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_append(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val)
+{
+ void *data;
+ long int v;
+ double d;
+ Eina_Bool b;
+
+ if (!arg_val)
+ {
+ _ecore_getopt_desc_print_error
+ (desc, _("missing parameter to append.\n"));
+ return EINA_FALSE;
+ }
+
+ if (!val->listp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+
+ switch (desc->action_param.append_type)
+ {
+ case ECORE_GETOPT_TYPE_STR:
+ data = strdup(arg_val);
+ break;
+
+ case ECORE_GETOPT_TYPE_BOOL:
+ {
+ if (_ecore_getopt_parse_bool(arg_val, &b))
+ {
+ data = malloc(sizeof(Eina_Bool));
+ if (data)
+ *(Eina_Bool *)data = b;
+ }
+ else
+ {
+ _ecore_getopt_desc_print_error(desc, _("unknown boolean value %s.\n"), arg_val);
+ return EINA_FALSE;
+ }
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_SHORT:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(short));
+ if (data)
+ *(short *)data = (short)v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_INT:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(int));
+ if (data)
+ *(int *)data = (int)v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_LONG:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(long));
+ if (data)
+ *(long *)data = v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_USHORT:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(unsigned short));
+ if (data)
+ *(unsigned short *)data = (unsigned short)v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_UINT:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(unsigned int));
+ if (data)
+ *(unsigned int *)data = (unsigned int)v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_ULONG:
+ {
+ if (!_ecore_getopt_parse_long(arg_val, &v))
+ goto error;
+ data = malloc(sizeof(unsigned long));
+ if (data)
+ *(unsigned long *)data = v;
+ }
+ break;
+
+ case ECORE_GETOPT_TYPE_DOUBLE:
+ {
+ if (!_ecore_getopt_parse_double(arg_val, &d))
+ goto error;
+ data = malloc(sizeof(double));
+ if (data)
+ *(double *)data = d;
+ }
+ break;
+
+ default:
+ {
+ _ecore_getopt_desc_print_error(desc, _("could not parse value.\n"));
+ return EINA_FALSE;
+ }
+ }
+
+ *val->listp = eina_list_append(*val->listp, data);
+ return EINA_TRUE;
+
+error:
+ _ecore_getopt_desc_print_error
+ (desc, _("invalid number format %s\n"), arg_val);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_count(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (!val->intp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+
+ (*val->intp)++;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_callback(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val)
+{
+ const Ecore_Getopt_Desc_Callback *cb = &desc->action_param.callback;
+
+ switch (cb->arg_req)
+ {
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
+ arg_val = cb->def;
+ break;
+
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
+ if (!arg_val)
+ arg_val = cb->def;
+ break;
+
+ case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
+ break;
+ }
+
+ if (cb->arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ {
+ if ((!arg_val) || (arg_val[0] == '\0'))
+ {
+ _ecore_getopt_desc_print_error(desc, _("missing parameter.\n"));
+ return EINA_FALSE;
+ }
+
+ if (!val->ptrp)
+ {
+ _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+ return EINA_FALSE;
+ }
+ }
+
+ if (!cb->func)
+ {
+ _ecore_getopt_desc_print_error(desc, _("missing callback function!\n"));
+ return EINA_FALSE;
+ }
+
+ return cb->func(parser, desc, arg_val, (void *)cb->data, val);
+}
+
+static Eina_Bool
+_ecore_getopt_parse_help(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc EINA_UNUSED,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (val->boolp)
+ (*val->boolp) = EINA_TRUE;
+ ecore_getopt_help(stdout, parser);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_version(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (val->boolp)
+ (*val->boolp) = EINA_TRUE;
+ if (!parser->version)
+ {
+ _ecore_getopt_desc_print_error(desc, _("no version was defined.\n"));
+ return EINA_FALSE;
+ }
+ _ecore_getopt_version(stdout, parser);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_copyright(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (val->boolp)
+ (*val->boolp) = EINA_TRUE;
+ if (!parser->copyright)
+ {
+ _ecore_getopt_desc_print_error(desc, _("no copyright was defined.\n"));
+ return EINA_FALSE;
+ }
+ _ecore_getopt_copyright(stdout, parser);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_license(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *val,
+ const char *arg_val EINA_UNUSED)
+{
+ if (val->boolp)
+ (*val->boolp) = EINA_TRUE;
+ if (!parser->license)
+ {
+ _ecore_getopt_desc_print_error(desc, _("no license was defined.\n"));
+ return EINA_FALSE;
+ }
+ _ecore_getopt_license(stdout, parser);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_desc_handle(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *desc,
+ Ecore_Getopt_Value *value,
+ const char *arg_val)
+{
+ switch (desc->action)
+ {
+ case ECORE_GETOPT_ACTION_STORE:
+ return _ecore_getopt_parse_store(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_STORE_CONST:
+ return _ecore_getopt_parse_store_const(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_STORE_TRUE:
+ return _ecore_getopt_parse_store_true(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_STORE_FALSE:
+ return _ecore_getopt_parse_store_false(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_CHOICE:
+ return _ecore_getopt_parse_choice(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_APPEND:
+ return _ecore_getopt_parse_append(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_COUNT:
+ return _ecore_getopt_parse_count(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_CALLBACK:
+ return _ecore_getopt_parse_callback(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_HELP:
+ return _ecore_getopt_parse_help(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_VERSION:
+ return _ecore_getopt_parse_version(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_COPYRIGHT:
+ return _ecore_getopt_parse_copyright(parser, desc, value, arg_val);
+
+ case ECORE_GETOPT_ACTION_LICENSE:
+ return _ecore_getopt_parse_license(parser, desc, value, arg_val);
+
+ default:
+ return EINA_FALSE;
+ }
+}
+
+static Eina_Bool
+_ecore_getopt_parse_arg_long(const Ecore_Getopt *parser,
+ Ecore_Getopt_Value *values,
+ int argc EINA_UNUSED,
+ char **argv,
+ int *idx,
+ int *nonargs,
+ const char *arg)
+{
+ const Ecore_Getopt_Desc *desc;
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ const char *arg_val;
+ int desc_idx;
+ Ecore_Getopt_Value *value;
+ Eina_Bool ret;
+
+ desc = _ecore_getopt_parse_find_long(parser, arg);
+ if (!desc)
+ {
+ fprintf(stderr, _("ERROR: unknown option --%s, ignored.\n"), arg);
+ if (parser->strict)
+ return EINA_FALSE;
+
+ (*idx)++;
+ return EINA_TRUE;
+ }
+
+ (*idx)++;
+
+ arg_req = _ecore_getopt_desc_arg_requirement(desc);
+ if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ {
+ arg_val = strchr(arg, '=');
+ if (arg_val)
+ arg_val++;
+ else
+ {
+ if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
+ {
+ arg_val = argv[*idx];
+ (*idx)++;
+ }
+ else
+ arg_val = NULL;
+ }
+
+ if (arg_val && arg_val[0] == '\0')
+ arg_val = NULL;
+
+ if ((!arg_val) && (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
+ {
+ fprintf
+ (stderr, _("ERROR: option --%s requires an argument!\n"), arg);
+ if (parser->strict)
+ return EINA_FALSE;
+ return EINA_TRUE;
+ }
+ }
+ else
+ arg_val = NULL;
+
+ desc_idx = desc - parser->descs;
+ value = values + desc_idx;
+ ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
+ if ((!ret) && parser->strict)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_arg_short(const Ecore_Getopt *parser,
+ Ecore_Getopt_Value *values,
+ int argc EINA_UNUSED,
+ char **argv,
+ int *idx,
+ int *nonargs,
+ const char *arg)
+{
+ int run = 1;
+ while (run && (arg[0] != '\0'))
+ {
+ int opt = arg[0];
+ const Ecore_Getopt_Desc *desc;
+ Ecore_Getopt_Desc_Arg_Requirement arg_req;
+ const char *arg_val;
+ int desc_idx;
+ Ecore_Getopt_Value *value;
+ Eina_Bool ret;
+
+ desc = _ecore_getopt_parse_find_short(parser, arg[0]);
+ if (!desc)
+ {
+ fprintf
+ (stderr, _("ERROR: unknown option -%c, ignored.\n"), arg[0]);
+ if (parser->strict)
+ return EINA_FALSE;
+
+ arg++;
+ continue;
+ }
+
+ arg++;
+
+ arg_req = _ecore_getopt_desc_arg_requirement(desc);
+ if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+ {
+ (*idx)++;
+ run = 0;
+
+ if (arg[0] == '=')
+ arg_val = arg + 1;
+ else if (arg[0] != '\0')
+ arg_val = arg;
+ else
+ {
+ if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
+ {
+ arg_val = argv[*idx];
+ (*idx)++;
+ }
+ else
+ arg_val = NULL;
+ }
+
+ if (arg_val && arg_val[0] == '\0')
+ arg_val = NULL;
+
+ if ((!arg_val) &&
+ (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
+ {
+ fprintf
+ (stderr, _("ERROR: option -%c requires an argument!\n"),
+ opt);
+ if (parser->strict)
+ return EINA_FALSE;
+ return EINA_TRUE;
+ }
+ }
+ else
+ arg_val = NULL;
+
+ desc_idx = desc - parser->descs;
+ value = values + desc_idx;
+ ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
+ if ((!ret) && parser->strict)
+ return EINA_FALSE;
+ }
+
+ if (run)
+ (*idx)++;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_getopt_parse_arg(const Ecore_Getopt *parser,
+ Ecore_Getopt_Value *values,
+ int argc,
+ char **argv,
+ int *idx,
+ int *nonargs)
+{
+ char *arg = argv[*idx];
+
+ if (arg[0] != '-')
+ {
+ char **dst, **src, **src_end;
+
+ dst = argv + *idx;
+ src = dst + 1;
+ src_end = src + *nonargs - *idx - 1;
+
+ for (; src < src_end; src++, dst++)
+ *dst = *src;
+
+ *dst = arg;
+ (*nonargs)--;
+ return EINA_TRUE;
+ }
+
+ if (arg[1] == '-')
+ return _ecore_getopt_parse_arg_long(parser, values, argc, argv, idx, nonargs, arg + 2);
+ else
+ return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1);
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_short_other(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *orig)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ const char c = orig->shortname;
+
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ {
+ if (desc == orig)
+ return NULL;
+
+ if (c == desc->shortname)
+ return desc;
+ }
+
+ return NULL;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_long_other(const Ecore_Getopt *parser,
+ const Ecore_Getopt_Desc *orig)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ const char *name = orig->longname;
+
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ {
+ if (desc == orig)
+ return NULL;
+
+ if (desc->longname && (strcmp(name, desc->longname) == 0))
+ return desc;
+ }
+
+ return NULL;
+}
+
+/**
+ * Check parser for duplicate entries, print them out.
+ *
+ * @return @c EINA_TRUE if there are duplicates, @c EINA_FALSE otherwise.
+ * @param parser The parser to be checked.
+ */
+EAPI Eina_Bool
+ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ {
+ if (desc->shortname)
+ {
+ const Ecore_Getopt_Desc *other;
+ other = _ecore_getopt_parse_find_short_other(parser, desc);
+ if (other)
+ {
+ _ecore_getopt_desc_print_error(desc, "short name -%c already exists.", desc->shortname);
+
+ if (other->longname)
+ fprintf(stderr, " Other is --%s.\n", other->longname);
+ else
+ fputc('\n', stderr);
+ return EINA_TRUE;
+ }
+ }
+
+ if (desc->longname)
+ {
+ const Ecore_Getopt_Desc *other;
+ other = _ecore_getopt_parse_find_long_other(parser, desc);
+ if (other)
+ {
+ _ecore_getopt_desc_print_error(desc, "long name --%s already exists.", desc->longname);
+
+ if (other->shortname)
+ fprintf(stderr, " Other is -%c.\n", other->shortname);
+ else
+ fputc('\n', stderr);
+ return EINA_TRUE;
+ }
+ }
+ }
+ return EINA_FALSE;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_find_help(const Ecore_Getopt *parser)
+{
+ const Ecore_Getopt_Desc *desc = parser->descs;
+ for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+ if (desc->action == ECORE_GETOPT_ACTION_HELP)
+ return desc;
+ return NULL;
+}
+
+/**
+ * Parse command line parameters.
+ *
+ * Walks the command line parameters and parse them based on @a parser
+ * description, doing actions based on @c parser->descs->action, like
+ * showing help text, license, copyright, storing values in values and
+ * so on.
+ *
+ * It is expected that values is of the same size than @c parser->descs,
+ * options that do not need a value it will be left untouched.
+ *
+ * All values are expected to be initialized before use. Options with
+ * action @c ECORE_GETOPT_ACTION_STORE and non required arguments
+ * (others than @c ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES), are expected
+ * to provide a value in @c def to be used.
+ *
+ * The following actions will store @c 1 on value as a boolean
+ * (@c value->boolp) if it's not @c NULL to indicate these actions were
+ * executed:
+ * - @c ECORE_GETOPT_ACTION_HELP
+ * - @c ECORE_GETOPT_ACTION_VERSION
+ * - @c ECORE_GETOPT_ACTION_COPYRIGHT
+ * - @c ECORE_GETOPT_ACTION_LICENSE
+ *
+ * Just @c ECORE_GETOPT_ACTION_APPEND will allocate memory and thus
+ * need to be freed. For consistency between all of appended subtypes,
+ * @c eina_list->data will contain an allocated memory with the value,
+ * that is, for @c ECORE_GETOPT_TYPE_STR it will contain a copy of the
+ * argument, @c ECORE_GETOPT_TYPE_INT a pointer to an allocated
+ * integer and so on.
+ *
+ * If parser is in strict mode (see @c Ecore_Getopt->strict), then any
+ * error will abort parsing and @c -1 is returned. Otherwise it will try
+ * to continue as far as possible.
+ *
+ * This function may reorder @a argv elements.
+ *
+ * Translation of help strings (description), metavar, usage, license
+ * and copyright may be translated, standard/global gettext() call
+ * will be applied on them if ecore was compiled with such support.
+ *
+ * @param parser description of how to work.
+ * @param values where to store values, it is assumed that this is a vector
+ * of the same size as @c parser->descs. Values should be previously
+ * initialized.
+ * @param argc how many elements in @a argv. If not provided it will be
+ * retrieved with ecore_app_args_get().
+ * @param argv command line parameters.
+ *
+ * @return index of first non-option parameter or -1 on error.
+ */
+EAPI int
+ecore_getopt_parse(const Ecore_Getopt *parser,
+ Ecore_Getopt_Value *values,
+ int argc,
+ char **argv)
+{
+ int i, nonargs;
+
+ if (!parser)
+ {
+ fputs(_("ERROR: no parser provided.\n"), stderr);
+ return -1;
+ }
+ if (!values)
+ {
+ fputs(_("ERROR: no values provided.\n"), stderr);
+ return -1;
+ }
+
+ if ((argc < 1) || (!argv))
+ ecore_app_args_get(&argc, &argv);
+
+ if (argc < 1)
+ {
+ fputs(_("ERROR: no arguments provided.\n"), stderr);
+ return -1;
+ }
+
+ if (argv[0])
+ prog = argv[0];
+ else
+ prog = parser->prog;
+
+ nonargs = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv);
+ if (nonargs < 0)
+ goto error;
+
+ if (nonargs > argc)
+ nonargs = argc;
+
+ i = 1;
+ while (i < nonargs)
+ if (!_ecore_getopt_parse_arg(parser, values, argc, argv, &i, &nonargs))
+ goto error;
+
+ return nonargs;
+
+error:
+ {
+ const Ecore_Getopt_Desc *help;
+ fputs(_("ERROR: invalid options found."), stderr);
+
+ help = _ecore_getopt_find_help(parser);
+ if (!help)
+ fputc('\n', stderr);
+ else if (help->longname)
+ fprintf(stderr, _(" See --%s.\n"), help->longname);
+ else
+ fprintf(stderr, _(" See -%c.\n"), help->shortname);
+ }
+
+ return -1;
+}
+
+/**
+ * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND.
+ *
+ * @param list pointer to list to be freed.
+ * @return always @c NULL, so you can easily make your list head @c NULL.
+ */
+EAPI Eina_List *
+ecore_getopt_list_free(Eina_List *list)
+{
+ void *data;
+
+ EINA_LIST_FREE(list, data)
+ free(data);
+ return NULL;
+}
+
+/**
+ * Helper ecore_getopt callback to parse geometry (x:y:w:h).
+ *
+ * @param parser This parameter isn't in use.
+ * @param desc This parameter isn't in use.
+ * @param str Geometry value
+ * @param data This parameter isn't in use.
+ * @param storage must be a pointer to @c Eina_Rectangle and will be used to
+ * store the four values passed in the given string.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect geometry value.
+ *
+ * @c callback_data value is ignored, you can safely use @c NULL.
+ */
+EAPI Eina_Bool
+ecore_getopt_callback_geometry_parse(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc EINA_UNUSED,
+ const char *str,
+ void *data EINA_UNUSED,
+ Ecore_Getopt_Value *storage)
+{
+ Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
+
+ if (sscanf(str, "%d:%d:%d:%d", &v->x, &v->y, &v->w, &v->h) != 4)
+ {
+ fprintf(stderr, _("ERROR: incorrect geometry value '%s'\n"), str);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+/**
+ * Helper ecore_getopt callback to parse geometry size (WxH).
+ *
+ * @param parser This parameter isn't in use.
+ * @param desc This parameter isn't in use.
+ * @param str size value
+ * @param data This parameter isn't in use.
+ * @param storage must be a pointer to @c Eina_Rectangle and will be used to
+ * store the two values passed in the given string and @c 0 in the x and y
+ * fields.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect size value.
+ *
+ * @c callback_data value is ignored, you can safely use @c NULL.
+ */
+EAPI Eina_Bool
+ecore_getopt_callback_size_parse(const Ecore_Getopt *parser EINA_UNUSED,
+ const Ecore_Getopt_Desc *desc EINA_UNUSED,
+ const char *str,
+ void *data EINA_UNUSED,
+ Ecore_Getopt_Value *storage)
+{
+ Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
+
+ if (sscanf(str, "%dx%d", &v->w, &v->h) != 2)
+ {
+ fprintf(stderr, _("ERROR: incorrect size value '%s'\n"), str);
+ return EINA_FALSE;
+ }
+ v->x = 0;
+ v->y = 0;
+
+ return EINA_TRUE;
+}
+
diff --git a/src/lib/ecore/ecore_glib.c b/src/lib/ecore/ecore_glib.c
new file mode 100644
index 0000000000..5b73180951
--- /dev/null
+++ b/src/lib/ecore/ecore_glib.c
@@ -0,0 +1,346 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+
+static Eina_Bool _ecore_glib_active = EINA_FALSE;
+static Ecore_Select_Function _ecore_glib_select_original;
+static GCond *_ecore_glib_cond = NULL;
+static GPollFD *_ecore_glib_fds = NULL;
+static size_t _ecore_glib_fds_size = 0;
+static const size_t ECORE_GLIB_FDS_INITIAL = 128;
+static const size_t ECORE_GLIB_FDS_STEP = 8;
+static const size_t ECORE_GLIB_FDS_MAX_FREE = 256;
+
+static Eina_Bool
+_ecore_glib_fds_resize(size_t size)
+{
+ void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size);
+
+ if (!tmp)
+ {
+ ERR("Could not realloc from %zu to %zu buckets.",
+ _ecore_glib_fds_size, size);
+ return EINA_FALSE;
+ }
+
+ _ecore_glib_fds = tmp;
+ _ecore_glib_fds_size = size;
+ return EINA_TRUE;
+}
+
+static int
+_ecore_glib_context_query(GMainContext *ctx,
+ int priority,
+ int *p_timer)
+{
+ int reqfds;
+
+ if (_ecore_glib_fds_size == 0)
+ {
+ if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1;
+ }
+
+ while (1)
+ {
+ size_t size;
+
+ reqfds = g_main_context_query
+ (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size);
+ if (reqfds <= (int)_ecore_glib_fds_size) break;
+
+ size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP;
+ if (!_ecore_glib_fds_resize(size)) return -1;
+ }
+
+ if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size)
+ {
+ size_t size;
+
+ size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * ECORE_GLIB_FDS_MAX_FREE;
+ _ecore_glib_fds_resize(size);
+ }
+
+ return reqfds;
+}
+
+static int
+_ecore_glib_context_poll_from(const GPollFD *pfds,
+ int count,
+ fd_set *rfds,
+ fd_set *wfds,
+ fd_set *efds)
+{
+ const GPollFD *itr = pfds, *itr_end = pfds + count;
+ int glib_fds = -1;
+
+ for (; itr < itr_end; itr++)
+ {
+ if (glib_fds < itr->fd)
+ glib_fds = itr->fd;
+
+ if (itr->events & G_IO_IN)
+ FD_SET(itr->fd, rfds);
+ if (itr->events & G_IO_OUT)
+ FD_SET(itr->fd, wfds);
+ if (itr->events & (G_IO_HUP | G_IO_ERR))
+ FD_SET(itr->fd, efds);
+ }
+
+ return glib_fds + 1;
+}
+
+static int
+_ecore_glib_context_poll_to(GPollFD *pfds,
+ int count,
+ const fd_set *rfds,
+ const fd_set *wfds,
+ const fd_set *efds,
+ int ready)
+{
+ GPollFD *itr = pfds, *itr_end = pfds + count;
+
+ for (; (itr < itr_end) && (ready > 0); itr++)
+ {
+ itr->revents = 0;
+ if (FD_ISSET(itr->fd, rfds) && (itr->events & G_IO_IN))
+ {
+ itr->revents |= G_IO_IN;
+ ready--;
+ }
+ if (FD_ISSET(itr->fd, wfds) && (itr->events & G_IO_OUT))
+ {
+ itr->revents |= G_IO_OUT;
+ ready--;
+ }
+ if (FD_ISSET(itr->fd, efds) && (itr->events & (G_IO_HUP | G_IO_ERR)))
+ {
+ itr->revents |= G_IO_ERR;
+ ready--;
+ }
+ }
+ return ready;
+}
+
+static int
+_ecore_glib_select__locked(GMainContext *ctx,
+ int ecore_fds,
+ fd_set *rfds,
+ fd_set *wfds,
+ fd_set *efds,
+ struct timeval *ecore_timeout)
+{
+ int priority, maxfds, glib_fds, reqfds, reqtimeout, ret;
+ struct timeval *timeout, glib_timeout;
+
+ g_main_context_prepare(ctx, &priority);
+ reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout);
+ if (reqfds < 0) goto error;
+
+ glib_fds = _ecore_glib_context_poll_from
+ (_ecore_glib_fds, reqfds, rfds, wfds, efds);
+
+ if (reqtimeout == -1)
+ timeout = ecore_timeout;
+ else
+ {
+ glib_timeout.tv_sec = reqtimeout / 1000;
+ glib_timeout.tv_usec = (reqtimeout % 1000) * 1000;
+
+ if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >))
+ timeout = &glib_timeout;
+ else
+ timeout = ecore_timeout;
+ }
+
+ maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds;
+ ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout);
+
+ ret = _ecore_glib_context_poll_to
+ (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret);
+
+ if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds))
+ g_main_context_dispatch(ctx);
+
+ return ret;
+
+error:
+ return _ecore_glib_select_original
+ (ecore_fds, rfds, wfds, efds, ecore_timeout);
+}
+
+static int
+_ecore_glib_select(int ecore_fds,
+ fd_set *rfds,
+ fd_set *wfds,
+ fd_set *efds,
+ struct timeval *ecore_timeout)
+{
+ GStaticMutex lock;
+ GMutex *mutex;
+ GMainContext *ctx;
+ int ret;
+
+ g_static_mutex_init(&lock);
+ mutex = g_static_mutex_get_mutex(&lock);
+ ctx = g_main_context_default();
+
+ if (g_main_context_acquire(ctx))
+ {
+ if (mutex) g_mutex_lock(mutex);
+ }
+ else
+ {
+ if (!_ecore_glib_cond)
+ _ecore_glib_cond = g_cond_new();
+
+ while (!g_main_context_wait(ctx, _ecore_glib_cond, mutex))
+ g_thread_yield();
+ }
+
+ ret = _ecore_glib_select__locked
+ (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout);
+
+ if (mutex) g_mutex_unlock(mutex);
+ g_main_context_release(ctx);
+ g_static_mutex_free(&lock);
+
+ return ret;
+}
+
+#endif
+
+void
+_ecore_glib_init(void)
+{
+}
+
+void
+_ecore_glib_shutdown(void)
+{
+#ifdef HAVE_GLIB
+ if (!_ecore_glib_active) return;
+ _ecore_glib_active = EINA_FALSE;
+
+ if (ecore_main_loop_select_func_get() == _ecore_glib_select)
+ ecore_main_loop_select_func_set(_ecore_glib_select_original);
+
+ if (_ecore_glib_fds)
+ {
+ free(_ecore_glib_fds);
+ _ecore_glib_fds = NULL;
+ }
+ _ecore_glib_fds_size = 0;
+
+ if (_ecore_glib_cond)
+ {
+ g_cond_free(_ecore_glib_cond);
+ _ecore_glib_cond = NULL;
+ }
+#endif
+}
+
+/**
+ * @addtogroup Ecore_Main_Loop_Group
+ *
+ * @}
+ */
+
+/**
+ * Request ecore to integrate GLib's main loop.
+ *
+ * This will add a small overhead during every main loop interaction
+ * by checking glib's default main context (used by its main loop). If
+ * it have events to be checked (timers, file descriptors or idlers),
+ * then these will be polled alongside with Ecore's own events, then
+ * dispatched before Ecore's. This is done by calling
+ * ecore_main_loop_select_func_set().
+ *
+ * This will cooperate with previously set
+ * ecore_main_loop_select_func_set() by calling the old
+ * function. Similarly, if you want to override
+ * ecore_main_loop_select_func_set() after main loop is integrated,
+ * call the new select function set by this call (get it by calling
+ * ecore_main_loop_select_func_get() right after
+ * ecore_main_loop_glib_integrate()).
+ *
+ * This is useful to use GMainLoop libraries, like GTK, GUPnP,
+ * LibSoup, GConf and more. Adobe Flash plugin and other plugins
+ * systems depend on this as well.
+ *
+ * Once initialized/integrated, it will be valid until Ecore is
+ * completely shut down.
+ *
+ * Example of use:
+ * @code
+ *
+ * int main(void)
+ * {
+ * ecore_init();
+ * ecore_main_loop_glib_integrate();
+ *
+ * // some code here
+ *
+ * ecore_main_loop_begin();
+ *
+ * ecore_shutdown();
+ *
+ * return 0;
+ * }
+ *
+ * @endcode
+ *
+ * @note This is only available if Ecore was compiled with GLib support.
+ * @note You don't need to call this function if Ecore was compiled with
+ * --enable-glib-integration-always.
+ *
+ * @return @c EINA_TRUE on success of @c EINA_FALSE if it failed,
+ * likely no GLib support in Ecore.
+ */
+EAPI Eina_Bool
+ecore_main_loop_glib_integrate(void)
+{
+#ifdef HAVE_GLIB
+ void *func;
+
+ if (_ecore_glib_active) return EINA_TRUE;
+ func = ecore_main_loop_select_func_get();
+ if (func == _ecore_glib_select) return EINA_TRUE;
+ _ecore_glib_select_original = func;
+ ecore_main_loop_select_func_set(_ecore_glib_select);
+ _ecore_glib_active = EINA_TRUE;
+ return EINA_TRUE;
+#else
+ ERR("No glib support");
+ return EINA_FALSE;
+#endif
+}
+
+Eina_Bool _ecore_glib_always_integrate = 1;
+
+/**
+ * Disable always integrating glib
+ *
+ * If ecore is compiled with --enable-glib-integration-always (to always
+ * call ecore_main_loop_glib_integrate() when ecore_init() is called), then
+ * calling this before calling ecore_init() will disable the integration.
+ * This is for apps that explicitly do not want this to happen for whatever
+ * reasons they may have.
+ */
+EAPI void
+ecore_main_loop_glib_always_integrate_disable(void)
+{
+ _ecore_glib_always_integrate = 0;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore/ecore_idle_enterer.c b/src/lib/ecore/ecore_idle_enterer.c
new file mode 100644
index 0000000000..e7d10e555a
--- /dev/null
+++ b/src/lib/ecore/ecore_idle_enterer.c
@@ -0,0 +1,313 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_IDLE_ENTERER_CLASS
+
+#define MY_CLASS_NAME "ecore_idle_enterer"
+
+EAPI Eo_Op ECORE_IDLE_ENTERER_BASE_ID = EO_NOOP;
+
+struct _Ecore_Idle_Enterer_Private_Data
+{
+ EINA_INLIST;
+ Ecore_Idle_Enterer *obj;
+ Ecore_Task_Cb func;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+typedef struct _Ecore_Idle_Enterer_Private_Data Ecore_Idle_Enterer_Private_Data;
+
+static Ecore_Idle_Enterer_Private_Data *idle_enterers = NULL;
+static Ecore_Idle_Enterer_Private_Data *idle_enterer_current = NULL;
+static int idle_enterers_delete_me = 0;
+
+static void *
+_ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer);
+
+/**
+ * @addtogroup Ecore_Idle_Group
+ *
+ * @{
+ */
+
+static Eina_Bool
+_ecore_idle_enterer_add(Ecore_Idle_Enterer *obj,
+ Ecore_Idle_Enterer_Private_Data *ie,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
+ }
+
+ ie->obj = obj;
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return EINA_FALSE;
+ }
+
+ ie->func = func;
+ ie->data = (void *)data;
+ return EINA_TRUE;
+}
+
+/**
+ * Add an idle enterer handler.
+ * @param func The function to call when entering an idle state.
+ * @param data The data to be passed to the @p func call
+ * @return A handle to the idle enterer callback if successful. Otherwise,
+ * NULL is returned.
+ * @note The function func will be called every time the main loop is entering
+ * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
+ * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer.
+ */
+EAPI Ecore_Idle_Enterer *
+ecore_idle_enterer_add(Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Idle_Enterer *ie = NULL;
+ ie = eo_add_custom(MY_CLASS, _ecore_parent, ecore_idle_enterer_after_constructor(func, data));
+ eo_unref(ie);
+ return ie;
+}
+
+static void
+_idle_enterer_after_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ _ecore_lock();
+ Ecore_Idle_Enterer_Private_Data *ie = _pd;
+ if (!_ecore_idle_enterer_add(obj, ie, func, data)) goto unlock;
+
+ idle_enterers = (Ecore_Idle_Enterer_Private_Data *)eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+
+unlock:
+ _ecore_unlock();
+}
+
+/**
+ * Add an idle enterer handler at the start of the list so it gets called earlier than others.
+ * @param func The function to call when entering an idle state.
+ * @param data The data to be passed to the @p func call
+ * @return A handle to the idle enterer callback if successful. Otherwise,
+ * NULL is returned.
+ * @note The function func will be called every time the main loop is entering
+ * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
+ * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer.
+ */
+EAPI Ecore_Idle_Enterer *
+ecore_idle_enterer_before_add(Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Idle_Enterer *ie = NULL;
+ ie = eo_add_custom(MY_CLASS, _ecore_parent, ecore_idle_enterer_before_constructor(func, data));
+ eo_unref(ie);
+ return ie;
+}
+
+static void
+_idle_enterer_before_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ _ecore_lock();
+ Ecore_Idle_Enterer_Private_Data *ie = _pd;
+ if (!_ecore_idle_enterer_add(obj, ie, func, data)) goto unlock;
+
+ idle_enterers = (Ecore_Idle_Enterer_Private_Data *)eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+
+unlock:
+ _ecore_unlock();
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+/**
+ * Delete an idle enterer callback.
+ * @param idle_enterer The idle enterer to delete
+ * @return The data pointer passed to the idler enterer callback on success.
+ * NULL otherwise.
+ */
+EAPI void *
+ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+
+ _ecore_lock();
+ data = _ecore_idle_enterer_del(idle_enterer);
+ _ecore_unlock();
+ return data;
+}
+
+/**
+ * @}
+ */
+
+
+static void *
+_ecore_idle_enterer_del(Ecore_Idle_Enterer *obj)
+{
+ Ecore_Idle_Enterer_Private_Data *idle_enterer = eo_data_get(obj, MY_CLASS);
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_enterer->delete_me, NULL);
+ idle_enterer->delete_me = 1;
+ idle_enterers_delete_me = 1;
+ return idle_enterer->data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Idle_Enterer_Private_Data *idle_enterer = _pd;
+
+ idle_enterer->delete_me = 1;
+ idle_enterers_delete_me = 1;
+
+ eo_do_super(obj, eo_destructor());
+}
+
+void
+_ecore_idle_enterer_shutdown(void)
+{
+ Ecore_Idle_Enterer_Private_Data *ie;
+ while ((ie = idle_enterers))
+ {
+ idle_enterers = (Ecore_Idle_Enterer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(idle_enterers));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ idle_enterers_delete_me = 0;
+ idle_enterer_current = NULL;
+}
+
+void
+_ecore_idle_enterer_call(void)
+{
+ if (!idle_enterer_current)
+ {
+ /* regular main loop, start from head */
+ idle_enterer_current = idle_enterers;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ idle_enterer_current =
+ (Ecore_Idle_Enterer_Private_Data *)EINA_INLIST_GET(idle_enterer_current)->next;
+ }
+
+ while (idle_enterer_current)
+ {
+ Ecore_Idle_Enterer_Private_Data *ie = (Ecore_Idle_Enterer_Private_Data *)idle_enterer_current;
+ if (!ie->delete_me)
+ {
+ ie->references++;
+ if (!_ecore_call_task_cb(ie->func, ie->data))
+ {
+ if (!ie->delete_me) _ecore_idle_enterer_del(ie->obj);
+ }
+ ie->references--;
+ }
+ if (idle_enterer_current) /* may have changed in recursive main loops */
+ idle_enterer_current =
+ (Ecore_Idle_Enterer_Private_Data *)EINA_INLIST_GET(idle_enterer_current)->next;
+ }
+ if (idle_enterers_delete_me)
+ {
+ Ecore_Idle_Enterer_Private_Data *l;
+ int deleted_idler_enterers_in_use = 0;
+
+ for (l = idle_enterers; l; )
+ {
+ Ecore_Idle_Enterer_Private_Data *ie = l;
+ l = (Ecore_Idle_Enterer_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (ie->delete_me)
+ {
+ if (ie->references)
+ {
+ deleted_idler_enterers_in_use++;
+ continue;
+ }
+
+ idle_enterers = (Ecore_Idle_Enterer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ }
+ if (!deleted_idler_enterers_in_use)
+ idle_enterers_delete_me = 0;
+ }
+}
+
+int
+_ecore_idle_enterer_exist(void)
+{
+ if (idle_enterers) return 1;
+ return 0;
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+ EO_OP_FUNC(ECORE_IDLE_ENTERER_ID(ECORE_IDLE_ENTERER_SUB_ID_AFTER_CONSTRUCTOR), _idle_enterer_after_constructor),
+ EO_OP_FUNC(ECORE_IDLE_ENTERER_ID(ECORE_IDLE_ENTERER_SUB_ID_BEFORE_CONSTRUCTOR), _idle_enterer_before_constructor),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_IDLE_ENTERER_SUB_ID_AFTER_CONSTRUCTOR, "Add an idle enterer handler."),
+ EO_OP_DESCRIPTION(ECORE_IDLE_ENTERER_SUB_ID_BEFORE_CONSTRUCTOR, "Add an idle enterer handler at the start of the list so it gets called earlier than others."),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_IDLE_ENTERER_BASE_ID, op_desc, ECORE_IDLE_ENTERER_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Idle_Enterer_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_idle_enterer_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore/ecore_idle_exiter.c b/src/lib/ecore/ecore_idle_exiter.c
new file mode 100644
index 0000000000..8fd20e7a0a
--- /dev/null
+++ b/src/lib/ecore/ecore_idle_exiter.c
@@ -0,0 +1,264 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_IDLE_EXITER_CLASS
+
+#define MY_CLASS_NAME "ecore_idle_exiter"
+
+EAPI Eo_Op ECORE_IDLE_EXITER_BASE_ID = EO_NOOP;
+
+struct _Ecore_Idle_Exiter_Private_Data
+{
+ EINA_INLIST;
+ Ecore_Idle_Exiter *obj;
+ Ecore_Task_Cb func;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+
+typedef struct _Ecore_Idle_Exiter_Private_Data Ecore_Idle_Exiter_Private_Data;
+
+static Ecore_Idle_Exiter_Private_Data *idle_exiters = NULL;
+static Ecore_Idle_Exiter_Private_Data *idle_exiter_current = NULL;
+static int idle_exiters_delete_me = 0;
+
+static void *
+_ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter);
+
+/**
+ * @addtogroup Ecore_Idle_Group
+ *
+ * @{
+ */
+
+/**
+ * Add an idle exiter handler.
+ * @param func The function to call when exiting an idle state.
+ * @param data The data to be passed to the @p func call
+ * @return A handle to the idle exiter callback on success. NULL otherwise.
+ * @note The function func will be called every time the main loop is exiting
+ * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0
+ * (or ECORE_CALLBACK_CANCEL) deletes the idle exiter.
+ */
+EAPI Ecore_Idle_Exiter *
+ecore_idle_exiter_add(Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Idle_Exiter *ie = NULL;
+ ie = eo_add_custom(MY_CLASS, _ecore_parent, ecore_idle_exiter_constructor(func, data));
+ eo_unref(ie);
+ return ie;
+}
+
+static void
+_idle_exiter_constructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ _ecore_lock();
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ }
+
+ Ecore_Idle_Exiter_Private_Data *ie = _pd;
+
+ ie->obj = obj;
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return;
+ }
+
+ ie->func = func;
+ ie->data = (void *)data;
+
+ idle_exiters = (Ecore_Idle_Exiter_Private_Data *)eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+ _ecore_unlock();
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+/**
+ * Delete an idle exiter handler from the list to be run on exiting idle state.
+ * @param idle_exiter The idle exiter to delete
+ * @return The data pointer that was being being passed to the handler if
+ * successful. NULL otherwise.
+ */
+EAPI void *
+ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
+{
+ void *data;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+
+ _ecore_lock();
+ data = _ecore_idle_exiter_del(idle_exiter);
+ _ecore_unlock();
+ return data;
+}
+
+/**
+ * @}
+ */
+static void *
+_ecore_idle_exiter_del(Ecore_Idle_Exiter *obj)
+{
+ Ecore_Idle_Exiter_Private_Data *idle_exiter = eo_data_get(obj, MY_CLASS);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_exiter->delete_me, NULL);
+ idle_exiter->delete_me = 1;
+ idle_exiters_delete_me = 1;
+ return idle_exiter->data;
+}
+
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Idle_Exiter_Private_Data *idle_exiter = _pd;
+
+ idle_exiter->delete_me = 1;
+ idle_exiters_delete_me = 1;
+
+ eo_do_super(obj, eo_destructor());
+}
+
+void
+_ecore_idle_exiter_shutdown(void)
+{
+ Ecore_Idle_Exiter_Private_Data *ie;
+ while ((ie = idle_exiters))
+ {
+ idle_exiters = (Ecore_Idle_Exiter_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(idle_exiters));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ idle_exiters_delete_me = 0;
+ idle_exiter_current = NULL;
+}
+
+void
+_ecore_idle_exiter_call(void)
+{
+ if (!idle_exiter_current)
+ {
+ /* regular main loop, start from head */
+ idle_exiter_current = idle_exiters;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ idle_exiter_current =
+ (Ecore_Idle_Exiter_Private_Data *)EINA_INLIST_GET(idle_exiter_current)->next;
+ }
+
+ while (idle_exiter_current)
+ {
+ Ecore_Idle_Exiter_Private_Data *ie = (Ecore_Idle_Exiter_Private_Data *)idle_exiter_current;
+ if (!ie->delete_me)
+ {
+ ie->references++;
+ if (!_ecore_call_task_cb(ie->func, ie->data))
+ {
+ if (!ie->delete_me) _ecore_idle_exiter_del(ie->obj);
+ }
+ ie->references--;
+ }
+ if (idle_exiter_current) /* may have changed in recursive main loops */
+ idle_exiter_current =
+ (Ecore_Idle_Exiter_Private_Data *)EINA_INLIST_GET(idle_exiter_current)->next;
+ }
+ if (idle_exiters_delete_me)
+ {
+ Ecore_Idle_Exiter_Private_Data *l;
+ int deleted_idler_exiters_in_use = 0;
+
+ for (l = idle_exiters; l; )
+ {
+ Ecore_Idle_Exiter_Private_Data *ie = l;
+
+ l = (Ecore_Idle_Exiter_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (ie->delete_me)
+ {
+ if (ie->references)
+ {
+ deleted_idler_exiters_in_use++;
+ continue;
+ }
+
+ idle_exiters = (Ecore_Idle_Exiter_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ }
+ if (!deleted_idler_exiters_in_use)
+ idle_exiters_delete_me = 0;
+ }
+}
+
+int
+_ecore_idle_exiter_exist(void)
+{
+ if (idle_exiters) return 1;
+ return 0;
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+ EO_OP_FUNC(ECORE_IDLE_EXITER_ID(ECORE_IDLE_EXITER_SUB_ID_CONSTRUCTOR), _idle_exiter_constructor),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_IDLE_EXITER_SUB_ID_CONSTRUCTOR, "Add an idle exiter handler."),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_IDLE_EXITER_BASE_ID, op_desc, ECORE_IDLE_EXITER_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Idle_Exiter_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_idle_exiter_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore/ecore_idler.c b/src/lib/ecore/ecore_idler.c
new file mode 100644
index 0000000000..147b3c1880
--- /dev/null
+++ b/src/lib/ecore/ecore_idler.c
@@ -0,0 +1,247 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_IDLER_CLASS
+
+#define MY_CLASS_NAME "ecore_idler"
+
+EAPI Eo_Op ECORE_IDLER_BASE_ID = EO_NOOP;
+
+struct _Ecore_Idler_Private_Data
+{
+ EINA_INLIST;
+ Ecore_Idler *obj;
+ Ecore_Task_Cb func;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+
+typedef struct _Ecore_Idler_Private_Data Ecore_Idler_Private_Data;
+static Ecore_Idler_Private_Data *idlers = NULL;
+static Ecore_Idler_Private_Data *idler_current = NULL;
+static int idlers_delete_me = 0;
+
+static void *
+_ecore_idler_del(Ecore_Idler *idler);
+
+EAPI Ecore_Idler *
+ecore_idler_add(Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Idler *ie = NULL;
+
+ _ecore_lock();
+
+ ie = eo_add_custom(MY_CLASS, _ecore_parent, ecore_idler_constructor(func, data));
+ eo_unref(ie);
+
+ _ecore_unlock();
+ return ie;
+}
+
+static void
+_idler_constructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ }
+
+ Ecore_Idler_Private_Data *ie = _pd;
+
+ ie->obj = obj;
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return;
+ }
+
+ ie->func = func;
+ ie->data = (void *)data;
+ idlers = (Ecore_Idler_Private_Data *)eina_inlist_append(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie));
+}
+
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+EAPI void *
+ecore_idler_del(Ecore_Idler *idler)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+
+ _ecore_lock();
+ data = _ecore_idler_del(idler);
+ _ecore_unlock();
+ return data;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+static void *
+_ecore_idler_del(Ecore_Idler *obj)
+{
+ Ecore_Idler_Private_Data *idler = eo_data_get(obj, MY_CLASS);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(idler->delete_me, NULL);
+ idler->delete_me = 1;
+ idlers_delete_me = 1;
+ return idler->data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Idler_Private_Data *idler = _pd;
+
+ idler->delete_me = 1;
+ idlers_delete_me = 1;
+
+ eo_do_super(obj, eo_destructor());
+}
+
+void
+_ecore_idler_shutdown(void)
+{
+ Ecore_Idler_Private_Data *ie;
+ while ((ie = idlers))
+ {
+ idlers = (Ecore_Idler_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(idlers));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ idlers_delete_me = 0;
+ idler_current = NULL;
+}
+
+int
+_ecore_idler_all_call(void)
+{
+ if (!idler_current)
+ {
+ /* regular main loop, start from head */
+ idler_current = idlers;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ idler_current = (Ecore_Idler_Private_Data *)EINA_INLIST_GET(idler_current)->next;
+ }
+
+ while (idler_current)
+ {
+ Ecore_Idler_Private_Data *ie = (Ecore_Idler_Private_Data *)idler_current;
+ if (!ie->delete_me)
+ {
+ ie->references++;
+ if (!_ecore_call_task_cb(ie->func, ie->data))
+ {
+ if (!ie->delete_me) _ecore_idler_del(ie->obj);
+ }
+ ie->references--;
+ }
+ if (idler_current) /* may have changed in recursive main loops */
+ idler_current = (Ecore_Idler_Private_Data *)EINA_INLIST_GET(idler_current)->next;
+ }
+ if (idlers_delete_me)
+ {
+ Ecore_Idler_Private_Data *l;
+ int deleted_idlers_in_use = 0;
+ for (l = idlers; l; )
+ {
+ Ecore_Idler_Private_Data *ie = l;
+ l = (Ecore_Idler_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (ie->delete_me)
+ {
+ if (ie->references)
+ {
+ deleted_idlers_in_use++;
+ continue;
+ }
+
+ idlers = (Ecore_Idler_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie));
+
+ eo_parent_set(ie->obj, NULL);
+ if (eo_destructed_is(ie->obj))
+ eo_manual_free(ie->obj);
+ else
+ eo_manual_free_set(ie->obj, EINA_FALSE);
+ }
+ }
+ if (!deleted_idlers_in_use)
+ idlers_delete_me = 0;
+ }
+ if (idlers) return 1;
+ return 0;
+}
+
+int
+_ecore_idler_exist(void)
+{
+ if (idlers) return 1;
+ return 0;
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+ EO_OP_FUNC(ECORE_IDLER_ID(ECORE_IDLER_SUB_ID_CONSTRUCTOR), _idler_constructor),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_IDLER_SUB_ID_CONSTRUCTOR, "Add an idler handler."),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_IDLER_BASE_ID, op_desc, ECORE_IDLER_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Idler_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_idler_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore/ecore_job.c b/src/lib/ecore/ecore_job.c
new file mode 100644
index 0000000000..bc438b7209
--- /dev/null
+++ b/src/lib/ecore/ecore_job.c
@@ -0,0 +1,198 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_JOB_CLASS
+
+#define MY_CLASS_NAME "ecore_job"
+
+EAPI Eo_Op ECORE_JOB_BASE_ID = EO_NOOP;
+
+static Eina_Bool _ecore_job_event_handler(void *data,
+ int type,
+ void *ev);
+static void _ecore_job_event_free(void *data,
+ void *ev);
+
+static int ecore_event_job_type = 0;
+static Ecore_Event_Handler *_ecore_job_handler = NULL;
+
+typedef struct _Ecore_Job_Private_Data Ecore_Job_Private_Data;
+
+struct _Ecore_Job_Private_Data
+{
+ Ecore_Event *event;
+ Ecore_Cb func;
+ void *data;
+};
+
+void
+_ecore_job_init(void)
+{
+ ecore_event_job_type = ecore_event_type_new();
+ _ecore_job_handler = ecore_event_handler_add(ecore_event_job_type, _ecore_job_event_handler, NULL);
+}
+
+void
+_ecore_job_shutdown(void)
+{
+ _ecore_event_handler_del(_ecore_job_handler);
+ _ecore_job_handler = NULL;
+}
+
+/**
+ * @addtogroup Ecore_Job_Group
+ *
+ * @{
+ */
+
+/**
+ * Add a job to the event queue.
+ * @param func The function to call when the job gets handled.
+ * @param data Data pointer to be passed to the job function when the job is
+ * handled.
+ * @return The handle of the job. @c NULL is returned if the job could not be
+ * added to the queue.
+ * @note Once the job has been executed, the job handle is invalid.
+ */
+EAPI Ecore_Job *
+ecore_job_add(Ecore_Cb func,
+ const void *data)
+{
+ Ecore_Job *job = eo_add_custom(MY_CLASS, _ecore_parent, ecore_job_constructor(func, data));
+ eo_unref(job);
+ return job;
+}
+
+static void
+_job_constructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Cb func = va_arg(*list, Ecore_Cb);
+ const void *data = va_arg(*list, const void *);
+
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ }
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return;
+ }
+
+ Ecore_Job_Private_Data *job = _pd;
+
+ job->event = ecore_event_add(ecore_event_job_type, job, _ecore_job_event_free, obj);
+ if (!job->event)
+ {
+ eo_error_set(obj);
+ ERR("no event was assigned to object '%p' of class '%s'", obj, MY_CLASS_NAME);
+ return;
+ }
+ job->func = func;
+ job->data = (void *)data;
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+/**
+ * Delete a queued job that has not yet been executed.
+ * @param job Handle of the job to delete.
+ * @return The data pointer that was to be passed to the job.
+ */
+EAPI void *
+ecore_job_del(Ecore_Job *obj)
+{
+ void *data;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ Ecore_Job_Private_Data *job = eo_data_get(obj, MY_CLASS);
+ data = job->data;
+ ecore_event_del(job->event);
+ eo_parent_set(obj, NULL);
+ return data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ /*FIXME: check if ecore_event_del should be called from here*/
+ eo_do_super(obj, eo_destructor());
+}
+
+/**
+ * @}
+ */
+
+static Eina_Bool
+_ecore_job_event_handler(void *data EINA_UNUSED,
+ int type EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Job_Private_Data *job;
+
+ job = ev;
+ job->func(job->data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_job_event_free(void *data,
+ void *job EINA_UNUSED)
+{
+ eo_parent_set(data, NULL);
+
+ Ecore_Job *obj = data;
+
+ if (eo_destructed_is(obj))
+ eo_manual_free(obj);
+ else
+ eo_manual_free_set(obj, EINA_FALSE);
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+ EO_OP_FUNC(ECORE_JOB_ID(ECORE_JOB_SUB_ID_CONSTRUCTOR), _job_constructor),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_JOB_SUB_ID_CONSTRUCTOR, "Add a job to the event queue."),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_JOB_BASE_ID, op_desc, ECORE_JOB_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Job_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_job_class_get, &class_desc, EO_BASE_CLASS, NULL);
diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c
new file mode 100644
index 0000000000..cc7b0654a5
--- /dev/null
+++ b/src/lib/ecore/ecore_main.c
@@ -0,0 +1,2111 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <winsock2.h>
+# undef WIN32_LEAN_AND_MEAN
+# ifndef USER_TIMER_MINIMUM
+# define USER_TIMER_MINIMUM 0x0a
+# endif
+#endif
+
+#ifdef __SUNPRO_C
+# include <ieeefp.h>
+# include <string.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef _MSC_VER
+# include <float.h>
+#endif
+
+#ifdef HAVE_ISFINITE
+# define ECORE_FINITE(t) isfinite(t)
+#else
+# ifdef _MSC_VER
+# define ECORE_FINITE(t) _finite(t)
+# else
+# define ECORE_FINITE(t) finite(t)
+# endif
+#endif
+
+//#define FIX_HZ 1
+
+#ifdef FIX_HZ
+# ifndef _MSC_VER
+# include <sys/param.h>
+# endif
+# ifndef HZ
+# define HZ 100
+# endif
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#ifdef HAVE_SYS_EPOLL_H
+# define HAVE_EPOLL 1
+# include <sys/epoll.h>
+#else
+
+# define HAVE_EPOLL 0
+# define EPOLLIN 1
+# define EPOLLPRI 2
+# define EPOLLOUT 4
+# define EPOLLERR 8
+
+#define EPOLL_CTL_ADD 1
+#define EPOLL_CTL_DEL 2
+#define EPOLL_CTL_MOD 3
+
+typedef union epoll_data {
+ void *ptr;
+ int fd;
+ uint32_t u32;
+ uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event
+{
+ uint32_t events;
+ epoll_data_t data;
+};
+
+static inline int
+epoll_create(int size EINA_UNUSED)
+{
+ return -1;
+}
+
+static inline int
+epoll_wait(int epfd EINA_UNUSED,
+ struct epoll_event *events EINA_UNUSED,
+ int maxevents EINA_UNUSED,
+ int timeout EINA_UNUSED)
+{
+ return -1;
+}
+
+static inline int
+epoll_ctl(int epfd EINA_UNUSED,
+ int op EINA_UNUSED,
+ int fd EINA_UNUSED,
+ struct epoll_event *event EINA_UNUSED)
+{
+ return -1;
+}
+
+#endif
+
+#ifdef HAVE_SYS_TIMERFD_H
+# include <sys/timerfd.h>
+#else
+/* fallback code if we don't have real timerfd - reduces number of ifdefs */
+# ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 0 /* bogus value */
+# endif
+# ifndef TFD_NONBLOCK
+# define TFD_NONBLOCK 0 /* bogus value */
+# endif
+#endif /* HAVE_SYS_TIMERFD_H */
+
+#ifndef HAVE_TIMERFD_CREATE
+static inline int
+timerfd_create(int clockid EINA_UNUSED,
+ int flags EINA_UNUSED)
+{
+ return -1;
+}
+
+static inline int
+timerfd_settime(int fd EINA_UNUSED,
+ int flags EINA_UNUSED,
+ const struct itimerspec *new_value EINA_UNUSED,
+ struct itimerspec *old_value EINA_UNUSED)
+{
+ return -1;
+}
+
+#endif /* HAVE_TIMERFD_CREATE */
+
+#ifdef USE_G_MAIN_LOOP
+# include <glib.h>
+#endif
+
+#define NS_PER_SEC (1000.0 * 1000.0 * 1000.0)
+
+struct _Ecore_Fd_Handler
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ Ecore_Fd_Handler *next_ready;
+ int fd;
+ Ecore_Fd_Handler_Flags flags;
+ Ecore_Fd_Cb func;
+ void *data;
+ Ecore_Fd_Cb buf_func;
+ void *buf_data;
+ Ecore_Fd_Prep_Cb prep_func;
+ void *prep_data;
+ int references;
+ Eina_Bool read_active : 1;
+ Eina_Bool write_active : 1;
+ Eina_Bool error_active : 1;
+ Eina_Bool delete_me : 1;
+ Eina_Bool file : 1;
+#if defined(USE_G_MAIN_LOOP)
+ GPollFD gfd;
+#endif
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Fd_Handler);
+
+#ifdef _WIN32
+struct _Ecore_Win32_Handler
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ HANDLE h;
+ Ecore_Win32_Handle_Cb func;
+ void *data;
+ int references;
+ Eina_Bool delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Win32_Handler);
+#endif
+
+#ifndef USE_G_MAIN_LOOP
+static int _ecore_main_select(double timeout);
+#endif
+static void _ecore_main_prepare_handlers(void);
+static void _ecore_main_fd_handlers_cleanup(void);
+#ifndef _WIN32
+# ifndef USE_G_MAIN_LOOP
+static void _ecore_main_fd_handlers_bads_rem(void);
+# endif
+#endif
+static void _ecore_main_fd_handlers_call(void);
+static int _ecore_main_fd_handlers_buf_call(void);
+#ifndef USE_G_MAIN_LOOP
+static void _ecore_main_loop_iterate_internal(int once_only);
+#endif
+
+#ifdef _WIN32
+static int _ecore_main_win32_select(int nfds,
+ fd_set *readfds,
+ fd_set *writefds,
+ fd_set *exceptfds,
+ struct timeval *timeout);
+static void _ecore_main_win32_handlers_cleanup(void);
+#endif
+
+static int in_main_loop = 0;
+static int do_quit = 0;
+static Ecore_Fd_Handler *fd_handlers = NULL;
+static Ecore_Fd_Handler *fd_handler_current = NULL;
+static Eina_List *fd_handlers_with_prep = NULL;
+static Eina_List *file_fd_handlers = NULL;
+static Eina_List *fd_handlers_with_buffer = NULL;
+static Eina_List *fd_handlers_to_delete = NULL;
+
+/* single linked list of ready fdhs, terminated by loop to self */
+static Ecore_Fd_Handler *fd_handlers_to_call;
+static Ecore_Fd_Handler *fd_handlers_to_call_current;
+
+#ifdef _WIN32
+static Ecore_Win32_Handler *win32_handlers = NULL;
+static Ecore_Win32_Handler *win32_handler_current = NULL;
+static Eina_Bool win32_handlers_delete_me = EINA_FALSE;
+#endif
+
+#ifdef _WIN32
+Ecore_Select_Function main_loop_select = _ecore_main_win32_select;
+#else
+# if !defined EXOTIC_NO_SELECT
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# endif
+Ecore_Select_Function main_loop_select = select;
+# else
+Ecore_Select_Function main_loop_select = NULL;
+# endif
+#endif
+
+#ifndef USE_G_MAIN_LOOP
+static double t1 = 0.0;
+static double t2 = 0.0;
+#endif
+
+static int timer_fd = -1;
+static int epoll_fd = -1;
+static pid_t epoll_pid;
+
+#ifdef USE_G_MAIN_LOOP
+static GPollFD ecore_epoll_fd;
+static GPollFD ecore_timer_fd;
+static GSource *ecore_glib_source;
+static guint ecore_glib_source_id;
+static GMainLoop *ecore_main_loop;
+static gboolean ecore_idling;
+static gboolean _ecore_glib_idle_enterer_called;
+static gboolean ecore_fds_ready;
+#endif
+
+static inline void
+_ecore_fd_valid(void)
+{
+ if (HAVE_EPOLL && epoll_fd >= 0)
+ {
+ if (fcntl(epoll_fd, F_GETFD) < 0)
+ {
+ ERR("arghhh you caught me! report a backtrace to edevel!");
+ pause();
+ }
+ }
+}
+
+static inline void
+_ecore_try_add_to_call_list(Ecore_Fd_Handler *fdh)
+{
+ /* check if this fdh is already in the list */
+ if (fdh->next_ready)
+ return;
+ if (fdh->read_active || fdh->write_active || fdh->error_active)
+ {
+ /*
+ * make sure next_ready is non-null by pointing to ourselves
+ * use that to indicate this fdh is in the ready list
+ * insert at the head of the list to avoid trouble
+ */
+ fdh->next_ready = fd_handlers_to_call ? fd_handlers_to_call : fdh;
+ fd_handlers_to_call = fdh;
+ }
+}
+
+static inline int
+_ecore_get_epoll_fd(void)
+{
+ if (epoll_pid && epoll_pid != getpid())
+ {
+ /* forked! */
+ _ecore_main_loop_shutdown();
+ }
+ if (epoll_pid == 0 && epoll_fd < 0)
+ {
+ _ecore_main_loop_init();
+ }
+ return epoll_fd;
+}
+
+static inline int
+_ecore_epoll_add(int efd,
+ int fd,
+ int events,
+ void *ptr)
+{
+ struct epoll_event ev;
+
+ memset(&ev, 0, sizeof (ev));
+ ev.events = events;
+ ev.data.ptr = ptr;
+ INF("adding poll on %d %08x", fd, events);
+ return epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
+}
+
+static inline int
+_ecore_poll_events_from_fdh(Ecore_Fd_Handler *fdh)
+{
+ int events = 0;
+ if (fdh->flags & ECORE_FD_READ) events |= EPOLLIN;
+ if (fdh->flags & ECORE_FD_WRITE) events |= EPOLLOUT;
+ if (fdh->flags & ECORE_FD_ERROR) events |= EPOLLERR | EPOLLPRI;
+ return events;
+}
+
+#ifdef USE_G_MAIN_LOOP
+static inline int
+_gfd_events_from_fdh(Ecore_Fd_Handler *fdh)
+{
+ int events = 0;
+ if (fdh->flags & ECORE_FD_READ) events |= G_IO_IN;
+ if (fdh->flags & ECORE_FD_WRITE) events |= G_IO_OUT;
+ if (fdh->flags & ECORE_FD_ERROR) events |= G_IO_ERR;
+ return events;
+}
+
+#endif
+
+static inline int
+_ecore_main_fdh_poll_add(Ecore_Fd_Handler *fdh)
+{
+ int r = 0;
+
+ if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0)
+ {
+ r = _ecore_epoll_add(_ecore_get_epoll_fd(), fdh->fd,
+ _ecore_poll_events_from_fdh(fdh), fdh);
+ }
+ else
+ {
+#ifdef USE_G_MAIN_LOOP
+ fdh->gfd.fd = fdh->fd;
+ fdh->gfd.events = _gfd_events_from_fdh(fdh);
+ fdh->gfd.revents = 0;
+ INF("adding gpoll on %d %08x", fdh->fd, fdh->gfd.events);
+ g_source_add_poll(ecore_glib_source, &fdh->gfd);
+#endif
+ }
+ return r;
+}
+
+static inline void
+_ecore_main_fdh_poll_del(Ecore_Fd_Handler *fdh)
+{
+ if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0)
+ {
+ struct epoll_event ev;
+ int efd = _ecore_get_epoll_fd();
+
+ memset(&ev, 0, sizeof (ev));
+ INF("removing poll on %d", fdh->fd);
+ /* could get an EBADF if somebody closed the FD before removing it */
+ if ((epoll_ctl(efd, EPOLL_CTL_DEL, fdh->fd, &ev) < 0))
+ {
+ if (errno == EBADF)
+ {
+ WRN("fd %d was closed, can't remove from epoll - reinit!",
+ fdh->fd);
+ _ecore_main_loop_shutdown();
+ _ecore_main_loop_init();
+ }
+ else
+ {
+ ERR("Failed to delete epoll fd %d! (errno=%d)", fdh->fd, errno);
+ }
+ }
+ }
+ else
+ {
+#ifdef USE_G_MAIN_LOOP
+ fdh->gfd.fd = fdh->fd;
+ fdh->gfd.events = _gfd_events_from_fdh(fdh);
+ fdh->gfd.revents = 0;
+ INF("adding gpoll on %d %08x", fdh->fd, fdh->gfd.events);
+ g_source_add_poll(ecore_glib_source, &fdh->gfd);
+#endif
+ }
+}
+
+static inline int
+_ecore_main_fdh_poll_modify(Ecore_Fd_Handler *fdh)
+{
+ int r = 0;
+ if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0)
+ {
+ struct epoll_event ev;
+ int efd = _ecore_get_epoll_fd();
+
+ memset(&ev, 0, sizeof (ev));
+ ev.events = _ecore_poll_events_from_fdh(fdh);
+ ev.data.ptr = fdh;
+ INF("modifing epoll on %d to %08x", fdh->fd, ev.events);
+ r = epoll_ctl(efd, EPOLL_CTL_MOD, fdh->fd, &ev);
+ }
+ else
+ {
+#ifdef USE_G_MAIN_LOOP
+ fdh->gfd.fd = fdh->fd;
+ fdh->gfd.events = _gfd_events_from_fdh(fdh);
+ fdh->gfd.revents = 0;
+ INF("modifing gpoll on %d to %08x", fdh->fd, fdh->gfd.events);
+#endif
+ }
+ return r;
+}
+
+static inline int
+_ecore_main_fdh_epoll_mark_active(void)
+{
+ struct epoll_event ev[32];
+ int i, ret;
+ int efd = _ecore_get_epoll_fd();
+
+ memset(&ev, 0, sizeof (ev));
+ ret = epoll_wait(efd, ev, sizeof(ev) / sizeof(struct epoll_event), 0);
+ if (ret < 0)
+ {
+ if (errno == EINTR) return -1;
+ ERR("epoll_wait failed %d", errno);
+ return -1;
+ }
+
+ for (i = 0; i < ret; i++)
+ {
+ Ecore_Fd_Handler *fdh;
+
+ fdh = ev[i].data.ptr;
+ if (!ECORE_MAGIC_CHECK(fdh, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fdh, ECORE_MAGIC_FD_HANDLER,
+ "_ecore_main_fdh_epoll_mark_active");
+ continue;
+ }
+ if (fdh->delete_me)
+ {
+ ERR("deleted fd in epoll");
+ continue;
+ }
+
+ if (ev[i].events & EPOLLIN)
+ fdh->read_active = EINA_TRUE;
+ if (ev[i].events & EPOLLOUT)
+ fdh->write_active = EINA_TRUE;
+ if (ev[i].events & EPOLLERR)
+ fdh->error_active = EINA_TRUE;
+
+ _ecore_try_add_to_call_list(fdh);
+ }
+
+ return ret;
+}
+
+#ifdef USE_G_MAIN_LOOP
+
+static inline int
+_ecore_main_fdh_glib_mark_active(void)
+{
+ Ecore_Fd_Handler *fdh;
+ int ret = 0;
+
+ /* call the prepare callback for all handlers */
+ EINA_INLIST_FOREACH(fd_handlers, fdh)
+ {
+ if (fdh->delete_me)
+ continue;
+
+ if (fdh->gfd.revents & G_IO_IN)
+ fdh->read_active = EINA_TRUE;
+ if (fdh->gfd.revents & G_IO_OUT)
+ fdh->write_active = EINA_TRUE;
+ if (fdh->gfd.revents & G_IO_ERR)
+ fdh->error_active = EINA_TRUE;
+
+ _ecore_try_add_to_call_list(fdh);
+
+ if (fdh->gfd.revents & (G_IO_IN | G_IO_OUT | G_IO_ERR)) ret++;
+ }
+
+ return ret;
+}
+
+/* like we are about to enter main_loop_select in _ecore_main_select */
+static gboolean
+_ecore_main_gsource_prepare(GSource *source EINA_UNUSED,
+ gint *next_time)
+{
+ gboolean ready = FALSE;
+
+ _ecore_lock();
+ in_main_loop++;
+
+ if (!ecore_idling && !_ecore_glib_idle_enterer_called)
+ {
+ _ecore_time_loop_time = ecore_time_get();
+ _ecore_timer_expired_timers_call(_ecore_time_loop_time);
+ _ecore_timer_cleanup();
+
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ _ecore_glib_idle_enterer_called = FALSE;
+
+ if (fd_handlers_with_buffer)
+ _ecore_main_fd_handlers_buf_call();
+ }
+
+ _ecore_signal_received_process();
+
+ /* don't check fds if somebody quit */
+ if (g_main_loop_is_running(ecore_main_loop))
+ {
+ /* only set idling state in dispatch */
+ if (ecore_idling && !_ecore_idler_exist() && !_ecore_event_exist())
+ {
+ if (_ecore_timers_exists())
+ {
+ int r = -1;
+ double t = _ecore_timer_next_get();
+ if (timer_fd >= 0 && t > 0.0)
+ {
+ struct itimerspec ts;
+
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+ ts.it_value.tv_sec = t;
+ ts.it_value.tv_nsec = fmod(t * NS_PER_SEC, NS_PER_SEC);
+
+ /* timerfd cannot sleep for 0 time */
+ if (ts.it_value.tv_sec || ts.it_value.tv_nsec)
+ {
+ r = timerfd_settime(timer_fd, 0, &ts, NULL);
+ if (r < 0)
+ {
+ ERR("timer set returned %d (errno=%d)", r, errno);
+ close(timer_fd);
+ timer_fd = -1;
+ }
+ else
+ INF("sleeping for %ld s %06ldus",
+ ts.it_value.tv_sec,
+ ts.it_value.tv_nsec / 1000);
+ }
+ }
+ if (r == -1)
+ {
+ *next_time = ceil(t * 1000.0);
+ if (t == 0.0)
+ ready = TRUE;
+ }
+ }
+ else
+ *next_time = -1;
+ }
+ else
+ {
+ *next_time = 0;
+ if (_ecore_event_exist())
+ ready = TRUE;
+ }
+
+ if (fd_handlers_with_prep)
+ _ecore_main_prepare_handlers();
+ }
+ else
+ ready = TRUE;
+
+ in_main_loop--;
+ INF("leave, timeout = %d", *next_time);
+ _ecore_unlock();
+
+ /* ready if we're not running (about to quit) */
+ return ready;
+}
+
+static gboolean
+_ecore_main_gsource_check(GSource *source EINA_UNUSED)
+{
+ gboolean ret = FALSE;
+
+ _ecore_lock();
+ in_main_loop++;
+
+ /* check if old timers expired */
+ if (ecore_idling && !_ecore_idler_exist() && !_ecore_event_exist())
+ {
+ if (timer_fd >= 0)
+ {
+ uint64_t count = 0;
+ int r = read(timer_fd, &count, sizeof count);
+ if (r == -1 && errno == EAGAIN)
+ ;
+ else if (r == sizeof count)
+ ret = TRUE;
+ else
+ {
+ /* unexpected things happened... fail back to old way */
+ ERR("timer read returned %d (errno=%d)", r, errno);
+ close(timer_fd);
+ timer_fd = -1;
+ }
+ }
+ }
+ else
+ ret = TRUE;
+
+ /* check if fds are ready */
+ if (HAVE_EPOLL && epoll_fd >= 0)
+ ecore_fds_ready = (_ecore_main_fdh_epoll_mark_active() > 0);
+ else
+ ecore_fds_ready = (_ecore_main_fdh_glib_mark_active() > 0);
+ _ecore_main_fd_handlers_cleanup();
+ if (ecore_fds_ready)
+ ret = TRUE;
+
+ /* check timers after updating loop time */
+ if (!ret && _ecore_timers_exists())
+ ret = (0.0 == _ecore_timer_next_get());
+
+ in_main_loop--;
+ _ecore_unlock();
+
+ return ret;
+}
+
+/* like we just came out of main_loop_select in _ecore_main_select */
+static gboolean
+_ecore_main_gsource_dispatch(GSource *source EINA_UNUSED,
+ GSourceFunc callback EINA_UNUSED,
+ gpointer user_data EINA_UNUSED)
+{
+ gboolean events_ready, timers_ready, idlers_ready;
+ double next_time;
+
+ _ecore_lock();
+ _ecore_time_loop_time = ecore_time_get();
+ _ecore_timer_enable_new();
+ next_time = _ecore_timer_next_get();
+
+ events_ready = _ecore_event_exist();
+ timers_ready = _ecore_timers_exists() && (0.0 == next_time);
+ idlers_ready = _ecore_idler_exist();
+
+ in_main_loop++;
+ INF("enter idling=%d fds=%d events=%d timers=%d (next=%.2f) idlers=%d",
+ ecore_idling, ecore_fds_ready, events_ready,
+ timers_ready, next_time, idlers_ready);
+
+ if (ecore_idling && events_ready)
+ {
+ _ecore_idle_exiter_call();
+ ecore_idling = 0;
+ }
+ else if (!ecore_idling && !events_ready)
+ {
+ ecore_idling = 1;
+ }
+
+ if (ecore_idling)
+ {
+ _ecore_idler_all_call();
+
+ events_ready = _ecore_event_exist();
+
+ if (ecore_fds_ready || events_ready || timers_ready)
+ {
+ _ecore_idle_exiter_call();
+ ecore_idling = 0;
+ }
+ }
+
+ /* process events */
+ if (!ecore_idling)
+ {
+ _ecore_main_fd_handlers_call();
+ if (fd_handlers_with_buffer)
+ _ecore_main_fd_handlers_buf_call();
+ _ecore_signal_received_process();
+ _ecore_event_call();
+ _ecore_main_fd_handlers_cleanup();
+
+ _ecore_timer_expired_timers_call(_ecore_time_loop_time);
+ _ecore_timer_cleanup();
+
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ _ecore_glib_idle_enterer_called = TRUE;
+
+ if (fd_handlers_with_buffer)
+ _ecore_main_fd_handlers_buf_call();
+ }
+
+ in_main_loop--;
+ _ecore_unlock();
+
+ return TRUE; /* what should be returned here? */
+}
+
+static void
+_ecore_main_gsource_finalize(GSource *source EINA_UNUSED)
+{
+}
+
+static GSourceFuncs ecore_gsource_funcs =
+{
+ .prepare = _ecore_main_gsource_prepare,
+ .check = _ecore_main_gsource_check,
+ .dispatch = _ecore_main_gsource_dispatch,
+ .finalize = _ecore_main_gsource_finalize,
+};
+
+#endif
+
+void
+_ecore_main_loop_init(void)
+{
+ epoll_fd = epoll_create(1);
+ if (epoll_fd < 0)
+ WRN("Failed to create epoll fd!");
+ epoll_pid = getpid();
+
+ /* add polls on all our file descriptors */
+ Ecore_Fd_Handler *fdh;
+ EINA_INLIST_FOREACH(fd_handlers, fdh)
+ {
+ if (fdh->delete_me)
+ continue;
+ _ecore_epoll_add(epoll_fd, fdh->fd,
+ _ecore_poll_events_from_fdh(fdh), fdh);
+ _ecore_main_fdh_poll_add(fdh);
+ }
+
+ /* setup for the g_main_loop only integration */
+#ifdef USE_G_MAIN_LOOP
+ ecore_glib_source = g_source_new(&ecore_gsource_funcs, sizeof (GSource));
+ if (!ecore_glib_source)
+ CRIT("Failed to create glib source for epoll!");
+ else
+ {
+ g_source_set_priority(ecore_glib_source, G_PRIORITY_HIGH_IDLE + 20);
+ if (HAVE_EPOLL && epoll_fd >= 0)
+ {
+ /* epoll multiplexes fds into the g_main_loop */
+ ecore_epoll_fd.fd = epoll_fd;
+ ecore_epoll_fd.events = G_IO_IN;
+ ecore_epoll_fd.revents = 0;
+ g_source_add_poll(ecore_glib_source, &ecore_epoll_fd);
+ }
+
+ /* timerfd gives us better than millisecond accuracy in g_main_loop */
+ timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+ if (timer_fd < 0)
+ WRN("failed to create timer fd!");
+ else
+ {
+ ecore_timer_fd.fd = timer_fd;
+ ecore_timer_fd.events = G_IO_IN;
+ ecore_timer_fd.revents = 0;
+ g_source_add_poll(ecore_glib_source, &ecore_timer_fd);
+ }
+
+ ecore_glib_source_id = g_source_attach(ecore_glib_source, NULL);
+ if (ecore_glib_source_id <= 0)
+ CRIT("Failed to attach glib source to default context");
+ }
+#endif
+}
+
+void
+_ecore_main_loop_shutdown(void)
+{
+#ifdef USE_G_MAIN_LOOP
+ if (ecore_glib_source)
+ {
+ g_source_destroy(ecore_glib_source);
+ ecore_glib_source = NULL;
+ }
+#endif
+
+ if (epoll_fd >= 0)
+ {
+ close(epoll_fd);
+ epoll_fd = -1;
+ }
+ epoll_pid = 0;
+
+ if (timer_fd >= 0)
+ {
+ close(timer_fd);
+ timer_fd = -1;
+ }
+}
+
+void *
+_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler)
+{
+ if (fd_handler->delete_me)
+ {
+ ERR("fdh %p deleted twice", fd_handler);
+ return NULL;
+ }
+
+ _ecore_main_fdh_poll_del(fd_handler);
+ fd_handler->delete_me = EINA_TRUE;
+ fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fd_handler);
+ if (fd_handler->prep_func && fd_handlers_with_prep)
+ fd_handlers_with_prep = eina_list_remove(fd_handlers_with_prep, fd_handler);
+ if (fd_handler->buf_func && fd_handlers_with_buffer)
+ fd_handlers_with_buffer = eina_list_remove(fd_handlers_with_buffer, fd_handler);
+ return fd_handler->data;
+}
+
+/**
+ * @addtogroup Ecore_Main_Loop_Group
+ *
+ * @{
+ */
+
+/**
+ * Runs a single iteration of the main loop to process everything on the
+ * queue.
+ *
+ * It does everything that is already done inside an @c Ecore main loop, like
+ * checking for expired timers, idlers, etc. But it will do it only once and
+ * return, instead of keep watching for new events.
+ *
+ * DO NOT use this function unless you are the person God comes to ask for
+ * advice when He has trouble managing the Universe.
+ *
+ * @see ecore_main_loop_iterate_may_block()
+ */
+EAPI void
+ecore_main_loop_iterate(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+#ifndef USE_G_MAIN_LOOP
+ _ecore_lock();
+ _ecore_time_loop_time = ecore_time_get();
+ _ecore_main_loop_iterate_internal(1);
+ _ecore_unlock();
+#else
+ g_main_context_iteration(NULL, 0);
+#endif
+}
+
+/**
+ * Runs a single iteration of the main loop to process everything on the
+ * queue with block/non-blocking status.
+ *
+ * @param may_block A flag if the main loop has a possibility of blocking.
+ * (@c EINA_TRUE = may block/@c EINA_FALSE = non block)
+ *
+ * This is an extension API for ecore_main_loop_iterate() with additional
+ * parameter. It does everything that is already done inside an
+ * @c Ecore main loop, like checking for expired timers, idlers, etc. But it
+ * will do it only once and return, instead of keep watching for new events.
+ *
+ * DO NOT use this function unless you are the person God comes to ask for
+ * advice when He has trouble managing the Universe.
+ *
+ * @see ecore_main_loop_iterate()
+ */
+EAPI int
+ecore_main_loop_iterate_may_block(int may_block)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+#ifndef USE_G_MAIN_LOOP
+ _ecore_lock();
+ _ecore_time_loop_time = ecore_time_get();
+in_main_loop++;
+ _ecore_main_loop_iterate_internal(!may_block);
+in_main_loop--;
+ _ecore_unlock();
+ return _ecore_event_exist();
+#else
+ return g_main_context_iteration(NULL, may_block);
+#endif
+}
+
+/**
+ * Runs the application main loop.
+ *
+ * This function will not return until @ref ecore_main_loop_quit is called. It
+ * will check for expired timers, idlers, file descriptors being watched by fd
+ * handlers, etc. Once everything is done, before entering again on idle state,
+ * any callback set as @c Idle_Enterer will be called.
+ *
+ * Each main loop iteration is done by calling ecore_main_loop_iterate()
+ * internally.
+ *
+ * The polling (select) function used can be changed with
+ * ecore_main_loop_select_func_set().
+ *
+ * The function used to check for file descriptors, events, and that has a
+ * timeout for the timers can be changed using
+ * ecore_main_loop_select_func_set().
+ */
+EAPI void
+ecore_main_loop_begin(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+#ifndef USE_G_MAIN_LOOP
+ _ecore_lock();
+ in_main_loop++;
+ _ecore_time_loop_time = ecore_time_get();
+ while (do_quit == 0) _ecore_main_loop_iterate_internal(0);
+ do_quit = 0;
+ in_main_loop--;
+ _ecore_unlock();
+#else
+ if (!do_quit)
+ {
+ if (!ecore_main_loop)
+ ecore_main_loop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(ecore_main_loop);
+ }
+ do_quit = 0;
+#endif
+}
+
+/**
+ * Quits the main loop once all the events currently on the queue have
+ * been processed.
+ *
+ * This function returns immediately, but will mark the ecore_main_loop_begin()
+ * function to return at the end of the current main loop iteration.
+ */
+EAPI void
+ecore_main_loop_quit(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ do_quit = 1;
+#ifdef USE_G_MAIN_LOOP
+ if (ecore_main_loop)
+ g_main_loop_quit(ecore_main_loop);
+#endif
+}
+
+/**
+ * Sets the function to use when monitoring multiple file descriptors,
+ * and waiting until one of more of the file descriptors before ready
+ * for some class of I/O operation.
+ *
+ * This function will be used instead of the system call select and
+ * could possible be used to integrate the Ecore event loop with an
+ * external event loop.
+ *
+ * @warning you don't know how to use, don't even try to use it.
+ *
+ * @param func The function to be used.
+ */
+EAPI void
+ecore_main_loop_select_func_set(Ecore_Select_Function func)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ main_loop_select = func;
+}
+
+/**
+ * Gets the select function set by ecore_select_func_set(),
+ * or the native select function if none was set.
+ *
+ */
+EAPI Ecore_Select_Function
+ecore_main_loop_select_func_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ return main_loop_select;
+}
+
+Ecore_Fd_Handler *
+_ecore_main_fd_handler_add(int fd,
+ Ecore_Fd_Handler_Flags flags,
+ Ecore_Fd_Cb func,
+ const void *data,
+ Ecore_Fd_Cb buf_func,
+ const void *buf_data)
+{
+ Ecore_Fd_Handler *fdh = NULL;
+
+ if ((fd < 0) || (flags == 0) || (!func)) return NULL;
+
+ fdh = ecore_fd_handler_calloc(1);
+ if (!fdh) return NULL;
+ ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER);
+ fdh->next_ready = NULL;
+ fdh->fd = fd;
+ fdh->flags = flags;
+ if (_ecore_main_fdh_poll_add(fdh) < 0)
+ {
+ int err = errno;
+ ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err));
+ ecore_fd_handler_mp_free(fdh);
+ return NULL;
+ }
+ fdh->read_active = EINA_FALSE;
+ fdh->write_active = EINA_FALSE;
+ fdh->error_active = EINA_FALSE;
+ fdh->delete_me = EINA_FALSE;
+ fdh->func = func;
+ fdh->data = (void *)data;
+ fdh->buf_func = buf_func;
+ if (buf_func)
+ fd_handlers_with_buffer = eina_list_append(fd_handlers_with_buffer, fdh);
+ fdh->buf_data = (void *)buf_data;
+ fd_handlers = (Ecore_Fd_Handler *)
+ eina_inlist_append(EINA_INLIST_GET(fd_handlers),
+ EINA_INLIST_GET(fdh));
+
+ return fdh;
+}
+
+EAPI Ecore_Fd_Handler *
+ecore_main_fd_handler_add(int fd,
+ Ecore_Fd_Handler_Flags flags,
+ Ecore_Fd_Cb func,
+ const void *data,
+ Ecore_Fd_Cb buf_func,
+ const void *buf_data)
+{
+ Ecore_Fd_Handler *fdh = NULL;
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ fdh = _ecore_main_fd_handler_add(fd, flags, func, data, buf_func, buf_data);
+ _ecore_unlock();
+ return fdh;
+}
+
+EAPI Ecore_Fd_Handler *
+ecore_main_fd_handler_file_add(int fd,
+ Ecore_Fd_Handler_Flags flags,
+ Ecore_Fd_Cb func,
+ const void *data,
+ Ecore_Fd_Cb buf_func,
+ const void *buf_data)
+{
+ Ecore_Fd_Handler *fdh = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+
+ if ((fd < 0) || (flags == 0) || (!func)) goto unlock;
+
+ fdh = ecore_fd_handler_calloc(1);
+ if (!fdh) goto unlock;
+ ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER);
+ fdh->next_ready = NULL;
+ fdh->fd = fd;
+ fdh->flags = flags;
+ fdh->file = EINA_TRUE;
+ if (_ecore_main_fdh_poll_add(fdh) < 0)
+ {
+ int err = errno;
+ ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err));
+ ecore_fd_handler_mp_free(fdh);
+ fdh = NULL;
+ goto unlock;
+ }
+ fdh->read_active = EINA_FALSE;
+ fdh->write_active = EINA_FALSE;
+ fdh->error_active = EINA_FALSE;
+ fdh->delete_me = EINA_FALSE;
+ fdh->func = func;
+ fdh->data = (void *)data;
+ fdh->buf_func = buf_func;
+ if (buf_func)
+ fd_handlers_with_buffer = eina_list_append(fd_handlers_with_buffer, fdh);
+ fdh->buf_data = (void *)buf_data;
+ fd_handlers = (Ecore_Fd_Handler *)
+ eina_inlist_append(EINA_INLIST_GET(fd_handlers),
+ EINA_INLIST_GET(fdh));
+ file_fd_handlers = eina_list_append(file_fd_handlers, fdh);
+unlock:
+ _ecore_unlock();
+
+ return fdh;
+}
+
+#ifdef _WIN32
+EAPI Ecore_Win32_Handler *
+ecore_main_win32_handler_add(void *h,
+ Ecore_Win32_Handle_Cb func,
+ const void *data)
+{
+ Ecore_Win32_Handler *wh;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!h || !func) return NULL;
+
+ wh = ecore_win32_handler_calloc(1);
+ if (!wh) return NULL;
+ ECORE_MAGIC_SET(wh, ECORE_MAGIC_WIN32_HANDLER);
+ wh->h = (HANDLE)h;
+ wh->delete_me = EINA_FALSE;
+ wh->func = func;
+ wh->data = (void *)data;
+ win32_handlers = (Ecore_Win32_Handler *)
+ eina_inlist_append(EINA_INLIST_GET(win32_handlers),
+ EINA_INLIST_GET(wh));
+ return wh;
+}
+
+#else
+EAPI Ecore_Win32_Handler *
+ecore_main_win32_handler_add(void *h EINA_UNUSED,
+ Ecore_Win32_Handle_Cb func EINA_UNUSED,
+ const void *data EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif
+
+EAPI void *
+ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler)
+{
+ void *ret = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+
+ if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+ "ecore_main_fd_handler_del");
+ goto unlock;
+ }
+ ret = _ecore_main_fd_handler_del(fd_handler);
+unlock:
+ _ecore_unlock();
+ return ret;
+}
+
+#ifdef _WIN32
+EAPI void *
+ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!ECORE_MAGIC_CHECK(win32_handler, ECORE_MAGIC_WIN32_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(win32_handler, ECORE_MAGIC_WIN32_HANDLER,
+ "ecore_main_win32_handler_del");
+ return NULL;
+ }
+ win32_handler->delete_me = EINA_TRUE;
+ win32_handlers_delete_me = EINA_TRUE;
+ return win32_handler->data;
+}
+
+#else
+EAPI void *
+ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif
+
+EAPI void
+ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler,
+ Ecore_Fd_Prep_Cb func,
+ const void *data)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+
+ if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+ "ecore_main_fd_handler_prepare_callback_set");
+ goto unlock;
+ }
+ fd_handler->prep_func = func;
+ fd_handler->prep_data = (void *)data;
+ if ((!fd_handlers_with_prep) ||
+ (fd_handlers_with_prep && (!eina_list_data_find(fd_handlers_with_prep, fd_handler))))
+ /* FIXME: THIS WILL NOT SCALE WITH LOTS OF PREP FUNCTIONS!!! */
+ fd_handlers_with_prep = eina_list_append(fd_handlers_with_prep, fd_handler);
+unlock:
+ _ecore_unlock();
+}
+
+EAPI int
+ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler)
+{
+ int fd = -1;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1);
+ _ecore_lock();
+
+ if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+ "ecore_main_fd_handler_fd_get");
+ goto unlock;
+ }
+ fd = fd_handler->fd;
+unlock:
+ _ecore_unlock();
+ return fd;
+}
+
+EAPI Eina_Bool
+ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler,
+ Ecore_Fd_Handler_Flags flags)
+{
+ int ret = EINA_FALSE;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
+ _ecore_lock();
+
+ if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+ "ecore_main_fd_handler_active_get");
+ goto unlock;
+ }
+ if ((flags & ECORE_FD_READ) && (fd_handler->read_active)) ret = EINA_TRUE;
+ if ((flags & ECORE_FD_WRITE) && (fd_handler->write_active)) ret = EINA_TRUE;
+ if ((flags & ECORE_FD_ERROR) && (fd_handler->error_active)) ret = EINA_TRUE;
+unlock:
+ _ecore_unlock();
+ return ret;
+}
+
+EAPI void
+ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler,
+ Ecore_Fd_Handler_Flags flags)
+{
+ int ret;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+
+ if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+ {
+ ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+ "ecore_main_fd_handler_active_set");
+ goto unlock;
+ }
+ fd_handler->flags = flags;
+ ret = _ecore_main_fdh_poll_modify(fd_handler);
+ if (ret < 0)
+ {
+ ERR("Failed to mod epoll fd %d: %s!", fd_handler->fd, strerror(ret));
+ }
+unlock:
+ _ecore_unlock();
+}
+
+/**
+ * @}
+ */
+
+void
+_ecore_main_shutdown(void)
+{
+ if (in_main_loop)
+ {
+ ERR("\n"
+ "*** ECORE WARNING: Calling ecore_shutdown() while still in the main loop.\n"
+ "*** Program may crash or behave strangely now.");
+ return;
+ }
+ while (fd_handlers)
+ {
+ Ecore_Fd_Handler *fdh;
+
+ fdh = fd_handlers;
+ fd_handlers = (Ecore_Fd_Handler *)eina_inlist_remove(EINA_INLIST_GET(fd_handlers),
+ EINA_INLIST_GET(fdh));
+ ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE);
+ ecore_fd_handler_mp_free(fdh);
+ }
+ if (fd_handlers_with_buffer)
+ fd_handlers_with_buffer = eina_list_free(fd_handlers_with_buffer);
+ if (fd_handlers_with_prep)
+ fd_handlers_with_prep = eina_list_free(fd_handlers_with_prep);
+ if (fd_handlers_to_delete)
+ fd_handlers_to_delete = eina_list_free(fd_handlers_to_delete);
+ if (file_fd_handlers)
+ file_fd_handlers = eina_list_free(file_fd_handlers);
+
+ fd_handlers_to_call = NULL;
+ fd_handlers_to_call_current = NULL;
+ fd_handlers_to_delete = NULL;
+ fd_handler_current = NULL;
+
+#ifdef _WIN32
+ while (win32_handlers)
+ {
+ Ecore_Win32_Handler *wh;
+
+ wh = win32_handlers;
+ win32_handlers = (Ecore_Win32_Handler *)eina_inlist_remove(EINA_INLIST_GET(win32_handlers),
+ EINA_INLIST_GET(wh));
+ ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE);
+ ecore_win32_handler_mp_free(wh);
+ }
+ win32_handlers_delete_me = EINA_FALSE;
+ win32_handler_current = NULL;
+#endif
+}
+
+static void
+_ecore_main_prepare_handlers(void)
+{
+ Ecore_Fd_Handler *fdh;
+ Eina_List *l, *l2;
+
+ /* call the prepare callback for all handlers with prep functions */
+ EINA_LIST_FOREACH_SAFE(fd_handlers_with_prep, l, l2, fdh)
+ {
+ if (!fdh)
+ {
+ fd_handlers_with_prep = eina_list_remove_list(l, fd_handlers_with_prep);
+ continue;
+ }
+ if (!fdh->delete_me && fdh->prep_func)
+ {
+ fdh->references++;
+ _ecore_call_prep_cb(fdh->prep_func, fdh->prep_data, fdh);
+ fdh->references--;
+ }
+ else
+ fd_handlers_with_prep = eina_list_remove_list(fd_handlers_with_prep, l);
+ }
+}
+
+#ifndef USE_G_MAIN_LOOP
+static int
+_ecore_main_select(double timeout)
+{
+ struct timeval tv, *t;
+ fd_set rfds, wfds, exfds;
+ Ecore_Fd_Handler *fdh;
+ Eina_List *l;
+ int max_fd;
+ int ret;
+
+ t = NULL;
+ if ((!ECORE_FINITE(timeout)) || (timeout == 0.0)) /* finite() tests for NaN, too big, too small, and infinity. */
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+ else if (timeout > 0.0)
+ {
+ int sec, usec;
+
+#ifdef FIX_HZ
+ timeout += (0.5 / HZ);
+ sec = (int)timeout;
+ usec = (int)((timeout - (double)sec) * 1000000);
+#else
+ sec = (int)timeout;
+ usec = (int)((timeout - (double)sec) * 1000000);
+#endif
+ tv.tv_sec = sec;
+ tv.tv_usec = usec;
+ t = &tv;
+ }
+ max_fd = 0;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&exfds);
+
+ /* call the prepare callback for all handlers */
+ if (fd_handlers_with_prep)
+ _ecore_main_prepare_handlers();
+
+ if (!HAVE_EPOLL || epoll_fd < 0)
+ {
+ EINA_INLIST_FOREACH(fd_handlers, fdh)
+ {
+ if (!fdh->delete_me)
+ {
+ if (fdh->flags & ECORE_FD_READ)
+ {
+ FD_SET(fdh->fd, &rfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (fdh->flags & ECORE_FD_WRITE)
+ {
+ FD_SET(fdh->fd, &wfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (fdh->flags & ECORE_FD_ERROR)
+ {
+ FD_SET(fdh->fd, &exfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* polling on the epoll fd will wake when an fd in the epoll set is active */
+ max_fd = _ecore_get_epoll_fd();
+ FD_SET(max_fd, &rfds);
+ }
+ EINA_LIST_FOREACH(file_fd_handlers, l, fdh)
+ if (!fdh->delete_me)
+ {
+ if (fdh->flags & ECORE_FD_READ)
+ {
+ FD_SET(fdh->fd, &rfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (fdh->flags & ECORE_FD_WRITE)
+ {
+ FD_SET(fdh->fd, &wfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (fdh->flags & ECORE_FD_ERROR)
+ {
+ FD_SET(fdh->fd, &exfds);
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (fdh->fd > max_fd) max_fd = fdh->fd;
+ }
+ if (_ecore_signal_count_get()) return -1;
+
+ _ecore_unlock();
+ ret = main_loop_select(max_fd + 1, &rfds, &wfds, &exfds, t);
+ _ecore_lock();
+
+ _ecore_time_loop_time = ecore_time_get();
+ if (ret < 0)
+ {
+#ifndef _WIN32
+ if (errno == EINTR) return -1;
+ else if (errno == EBADF)
+ _ecore_main_fd_handlers_bads_rem();
+#endif
+ }
+ if (ret > 0)
+ {
+ if (HAVE_EPOLL && epoll_fd >= 0)
+ _ecore_main_fdh_epoll_mark_active();
+ else
+ {
+ EINA_INLIST_FOREACH(fd_handlers, fdh)
+ {
+ if (!fdh->delete_me)
+ {
+ if (FD_ISSET(fdh->fd, &rfds))
+ fdh->read_active = EINA_TRUE;
+ if (FD_ISSET(fdh->fd, &wfds))
+ fdh->write_active = EINA_TRUE;
+ if (FD_ISSET(fdh->fd, &exfds))
+ fdh->error_active = EINA_TRUE;
+ _ecore_try_add_to_call_list(fdh);
+ }
+ }
+ }
+ EINA_LIST_FOREACH(file_fd_handlers, l, fdh)
+ {
+ if (!fdh->delete_me)
+ {
+ if (FD_ISSET(fdh->fd, &rfds))
+ fdh->read_active = EINA_TRUE;
+ if (FD_ISSET(fdh->fd, &wfds))
+ fdh->write_active = EINA_TRUE;
+ if (FD_ISSET(fdh->fd, &exfds))
+ fdh->error_active = EINA_TRUE;
+ _ecore_try_add_to_call_list(fdh);
+ }
+ }
+ _ecore_main_fd_handlers_cleanup();
+#ifdef _WIN32
+ _ecore_main_win32_handlers_cleanup();
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+#ifndef _WIN32
+# ifndef USE_G_MAIN_LOOP
+static void
+_ecore_main_fd_handlers_bads_rem(void)
+{
+ Ecore_Fd_Handler *fdh;
+ Eina_Inlist *l;
+ int found = 0;
+
+ ERR("Removing bad fds");
+ for (l = EINA_INLIST_GET(fd_handlers); l; )
+ {
+ fdh = (Ecore_Fd_Handler *)l;
+ l = l->next;
+ errno = 0;
+
+ if ((fcntl(fdh->fd, F_GETFD) < 0) && (errno == EBADF))
+ {
+ ERR("Found bad fd at index %d", fdh->fd);
+ if (fdh->flags & ECORE_FD_ERROR)
+ {
+ ERR("Fd set for error! calling user");
+ fdh->references++;
+ if (!_ecore_call_fd_cb(fdh->func, fdh->data, fdh))
+ {
+ ERR("Fd function err returned 0, remove it");
+ if (!fdh->delete_me)
+ {
+ fdh->delete_me = EINA_TRUE;
+ fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh);
+ }
+ found++;
+ }
+ fdh->references--;
+ }
+ else
+ {
+ ERR("Problematic fd found at %d! setting it for delete", fdh->fd);
+ if (!fdh->delete_me)
+ {
+ fdh->delete_me = EINA_TRUE;
+ fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh);
+ }
+
+ found++;
+ }
+ }
+ }
+ if (found == 0)
+ {
+# ifdef HAVE_GLIB
+ ERR("No bad fd found. Maybe a foreign fd from glib?");
+# else
+ ERR("No bad fd found. EEEK!");
+# endif
+ }
+ _ecore_main_fd_handlers_cleanup();
+}
+
+# endif
+#endif
+
+static void
+_ecore_main_fd_handlers_cleanup(void)
+{
+ Ecore_Fd_Handler *fdh;
+ Eina_List *l, *l2;
+
+ if (!fd_handlers_to_delete) return;
+ EINA_LIST_FOREACH_SAFE(fd_handlers_to_delete, l, l2, fdh)
+ {
+ if (!fdh)
+ {
+ fd_handlers_to_delete = eina_list_remove_list(l, fd_handlers_to_delete);
+ continue;
+ }
+ /* fdh->delete_me should be set for all fdhs at the start of the list */
+ if (fdh->references)
+ continue;
+ if (fdh->buf_func && fd_handlers_with_buffer)
+ fd_handlers_with_buffer = eina_list_remove(fd_handlers_with_buffer, fdh);
+ if (fdh->prep_func && fd_handlers_with_prep)
+ fd_handlers_with_prep = eina_list_remove(fd_handlers_with_prep, fdh);
+ fd_handlers = (Ecore_Fd_Handler *)
+ eina_inlist_remove(EINA_INLIST_GET(fd_handlers), EINA_INLIST_GET(fdh));
+ if (fdh->file)
+ file_fd_handlers = eina_list_remove(file_fd_handlers, fdh);
+ ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE);
+ ecore_fd_handler_mp_free(fdh);
+ fd_handlers_to_delete = eina_list_remove_list(fd_handlers_to_delete, l);
+ }
+}
+
+#ifdef _WIN32
+static void
+_ecore_main_win32_handlers_cleanup(void)
+{
+ Ecore_Win32_Handler *wh;
+ Eina_Inlist *l;
+ int deleted_in_use = 0;
+
+ if (!win32_handlers_delete_me) return;
+ for (l = EINA_INLIST_GET(win32_handlers); l; )
+ {
+ wh = (Ecore_Win32_Handler *)l;
+
+ l = l->next;
+ if (wh->delete_me)
+ {
+ if (wh->references)
+ {
+ deleted_in_use++;
+ continue;
+ }
+
+ win32_handlers = (Ecore_Win32_Handler *)
+ eina_inlist_remove(EINA_INLIST_GET(win32_handlers),
+ EINA_INLIST_GET(wh));
+ ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE);
+ ecore_win32_handler_mp_free(wh);
+ }
+ }
+ if (!deleted_in_use) win32_handlers_delete_me = EINA_FALSE;
+}
+
+#endif
+
+static void
+_ecore_main_fd_handlers_call(void)
+{
+ /* grab a new list */
+ if (!fd_handlers_to_call_current)
+ {
+ fd_handlers_to_call_current = fd_handlers_to_call;
+ fd_handlers_to_call = NULL;
+ }
+
+ while (fd_handlers_to_call_current)
+ {
+ Ecore_Fd_Handler *fdh = fd_handlers_to_call_current;
+
+ if (!fdh->delete_me)
+ {
+ if ((fdh->read_active) ||
+ (fdh->write_active) ||
+ (fdh->error_active))
+ {
+ fdh->references++;
+ if (!_ecore_call_fd_cb(fdh->func, fdh->data, fdh))
+ {
+ if (!fdh->delete_me)
+ {
+ fdh->delete_me = EINA_TRUE;
+ fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh);
+ }
+ }
+ fdh->references--;
+ _ecore_fd_valid();
+
+ fdh->read_active = EINA_FALSE;
+ fdh->write_active = EINA_FALSE;
+ fdh->error_active = EINA_FALSE;
+ }
+ }
+
+ /* stop when we point to ourselves */
+ if (fdh->next_ready == fdh)
+ {
+ fdh->next_ready = NULL;
+ fd_handlers_to_call_current = NULL;
+ break;
+ }
+
+ fd_handlers_to_call_current = fdh->next_ready;
+ fdh->next_ready = NULL;
+ }
+}
+
+static int
+_ecore_main_fd_handlers_buf_call(void)
+{
+ Ecore_Fd_Handler *fdh;
+ Eina_List *l, *l2;
+ int ret;
+
+ ret = 0;
+ EINA_LIST_FOREACH_SAFE(fd_handlers_with_buffer, l, l2, fdh)
+ {
+ if (!fdh)
+ {
+ fd_handlers_with_buffer = eina_list_remove_list(l, fd_handlers_with_buffer);
+ continue;
+ }
+ if ((!fdh->delete_me) && fdh->buf_func)
+ {
+ fdh->references++;
+ if (_ecore_call_fd_cb(fdh->buf_func, fdh->buf_data, fdh))
+ {
+ ret |= _ecore_call_fd_cb(fdh->func, fdh->data, fdh);
+ fdh->read_active = EINA_TRUE;
+ _ecore_try_add_to_call_list(fdh);
+ }
+ fdh->references--;
+ }
+ else
+ fd_handlers_with_buffer = eina_list_remove_list(fd_handlers_with_buffer, l);
+ }
+ return ret;
+}
+
+#ifndef USE_G_MAIN_LOOP
+
+enum {
+ SPIN_MORE,
+ SPIN_RESTART,
+ LOOP_CONTINUE
+};
+
+static int
+_ecore_main_loop_spin_core(void)
+{
+ /* as we are spinning we need to update loop time per spin */
+ _ecore_time_loop_time = ecore_time_get();
+ /* call all idlers, which returns false if no more idelrs exist */
+ if (!_ecore_idler_all_call()) return SPIN_RESTART;
+ /* sneaky - drop through or if checks - the first one to succeed
+ * drops through and returns "continue" so further ones dont run */
+ if ((_ecore_main_select(0.0) > 0) || (_ecore_event_exist()) ||
+ (_ecore_signal_count_get() > 0) || (do_quit))
+ return LOOP_CONTINUE;
+ /* default - spin more */
+ return SPIN_MORE;
+}
+
+static int
+_ecore_main_loop_spin_no_timers(void)
+{
+ /* if we have idlers we HAVE to spin and handle everything
+ * in a polling way - spin in a tight polling loop */
+ for (;; )
+ {
+ int action = _ecore_main_loop_spin_core();
+ if (action != SPIN_MORE) return action;
+ /* if an idler has added a timer then we need to go through
+ * the start of the spin cycle again to handle cases properly */
+ if (_ecore_timers_exists()) return SPIN_RESTART;
+ }
+ /* just contiune handling events etc. */
+ return LOOP_CONTINUE;
+}
+
+static int
+_ecore_main_loop_spin_timers(void)
+{
+ /* if we have idlers we HAVE to spin and handle everything
+ * in a polling way - spin in a tight polling loop */
+ for (;; )
+ {
+ int action = _ecore_main_loop_spin_core();
+ if (action != SPIN_MORE) return action;
+ /* if next timer expires now or in the past - stop spinning and
+ * continue the mainloop walk as our "select" timeout has
+ * expired now */
+ if (_ecore_timer_next_get() <= 0.0) return LOOP_CONTINUE;
+ }
+ /* just contiune handling events etc. */
+ return LOOP_CONTINUE;
+}
+
+static void
+_ecore_fps_marker_1(void)
+{
+ if (!_ecore_fps_debug) return;
+ t2 = ecore_time_get();
+ if ((t1 > 0.0) && (t2 > 0.0)) _ecore_fps_debug_runtime_add(t2 - t1);
+}
+
+static void
+_ecore_fps_marker_2(void)
+{
+ if (!_ecore_fps_debug) return;
+ t1 = ecore_time_get();
+}
+
+static void
+_ecore_main_loop_iterate_internal(int once_only)
+{
+ double next_time = -1.0;
+
+ in_main_loop++;
+ /* expire any timers */
+ _ecore_timer_expired_timers_call(_ecore_time_loop_time);
+ _ecore_timer_cleanup();
+
+ /* process signals into events .... */
+ _ecore_signal_received_process();
+ /* if as a result of timers/animators or signals we have accumulated
+ * events, then instantly handle them */
+ if (_ecore_event_exist())
+ {
+ /* but first conceptually enter an idle state */
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ /* now quickly poll to see which input fd's are active */
+ _ecore_main_select(0.0);
+ /* allow newly queued timers to expire from now on */
+ _ecore_timer_enable_new();
+ /* go straight to processing the events we had queued */
+ goto process_all;
+ }
+
+ if (once_only)
+ {
+ /* in once_only mode we should quickly poll for inputs, signals
+ * if we got any events or signals, allow new timers to process.
+ * use bitwise or to force both conditions to be tested and
+ * merged together */
+ if (_ecore_main_select(0.0) | _ecore_signal_count_get())
+ {
+ _ecore_timer_enable_new();
+ goto process_all;
+ }
+ }
+ else
+ {
+ /* call idle enterers ... */
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ }
+
+ /* if these calls caused any buffered events to appear - deal with them */
+ if (fd_handlers_with_buffer)
+ _ecore_main_fd_handlers_buf_call();
+
+ /* if there are any (buffered fd handling may generate them)
+ * then jump to processing them */
+ if (_ecore_event_exist())
+ {
+ _ecore_main_select(0.0);
+ _ecore_timer_enable_new();
+ goto process_all;
+ }
+
+ if (once_only)
+ {
+ /* in once_only mode enter idle here instead and then return */
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ _ecore_timer_enable_new();
+ goto done;
+ }
+
+ _ecore_fps_marker_1();
+
+ /* start of the sleeping or looping section */
+start_loop: /***************************************************************/
+ /* any timers re-added as a result of these are allowed to go */
+ _ecore_timer_enable_new();
+ /* if we have been asked to quit the mainloop then exit at this point */
+ if (do_quit)
+ {
+ _ecore_timer_enable_new();
+ goto done;
+ }
+ if (!_ecore_event_exist())
+ {
+ /* init flags */
+ next_time = _ecore_timer_next_get();
+ /* no idlers */
+ if (!_ecore_idler_exist())
+ {
+ /* sleep until timeout or forever (-1.0) waiting for on fds */
+ _ecore_main_select(next_time);
+ }
+ else
+ {
+ int action = LOOP_CONTINUE;
+
+ /* no timers - spin */
+ if (next_time < 0) action = _ecore_main_loop_spin_no_timers();
+ /* timers - spin */
+ else action = _ecore_main_loop_spin_timers();
+ if (action == SPIN_RESTART) goto start_loop;
+ }
+ }
+ _ecore_fps_marker_2();
+
+ /* actually wake up and deal with input, events etc. */
+process_all: /***********************************************************/
+
+ /* we came out of our "wait state" so idle has exited */
+ if (!once_only) _ecore_idle_exiter_call();
+ /* call the fd handler per fd that became alive... */
+ /* this should read or write any data to the monitored fd and then */
+ /* post events onto the ecore event pipe if necessary */
+ _ecore_main_fd_handlers_call();
+ if (fd_handlers_with_buffer) _ecore_main_fd_handlers_buf_call();
+ /* process signals into events .... */
+ _ecore_signal_received_process();
+ /* handle events ... */
+ _ecore_event_call();
+ _ecore_main_fd_handlers_cleanup();
+
+ if (once_only)
+ {
+ /* if in once_only mode handle idle exiting */
+ _ecore_idle_enterer_call();
+ _ecore_throttle();
+ }
+
+done: /*******************************************************************/
+ in_main_loop--;
+}
+
+#endif
+
+#ifdef _WIN32
+static int
+_ecore_main_win32_select(int nfds EINA_UNUSED,
+ fd_set *readfds,
+ fd_set *writefds,
+ fd_set *exceptfds,
+ struct timeval *tv)
+{
+ HANDLE objects[MAXIMUM_WAIT_OBJECTS];
+ int sockets[MAXIMUM_WAIT_OBJECTS];
+ Ecore_Fd_Handler *fdh;
+ Ecore_Win32_Handler *wh;
+ unsigned int objects_nbr = 0;
+ unsigned int handles_nbr = 0;
+ unsigned int events_nbr = 0;
+ DWORD result;
+ DWORD timeout;
+ MSG msg;
+ unsigned int i;
+ int res;
+
+ /* Create an event object per socket */
+ EINA_INLIST_FOREACH(fd_handlers, fdh)
+ {
+ WSAEVENT event;
+ long network_event;
+
+ network_event = 0;
+ if (readfds)
+ {
+ if (FD_ISSET(fdh->fd, readfds))
+ network_event |= FD_READ;
+ }
+ if (writefds)
+ {
+ if (FD_ISSET(fdh->fd, writefds))
+ network_event |= FD_WRITE;
+ }
+ if (exceptfds)
+ {
+ if (FD_ISSET(fdh->fd, exceptfds))
+ network_event |= FD_OOB;
+ }
+
+ if (network_event)
+ {
+ event = WSACreateEvent();
+ WSAEventSelect(fdh->fd, event, network_event);
+ objects[objects_nbr] = event;
+ sockets[events_nbr] = fdh->fd;
+ events_nbr++;
+ objects_nbr++;
+ }
+ }
+
+ /* store the HANDLEs in the objects to wait for */
+ EINA_INLIST_FOREACH(win32_handlers, wh)
+ {
+ objects[objects_nbr] = wh->h;
+ handles_nbr++;
+ objects_nbr++;
+ }
+
+ /* Empty the queue before waiting */
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ /* Wait for any message sent or posted to this queue */
+ /* or for one of the passed handles be set to signaled. */
+ if (!tv)
+ timeout = INFINITE;
+ else
+ timeout = (DWORD)((tv->tv_sec * 1000.0) + (tv->tv_usec / 1000.0));
+
+ if (timeout == 0) return 0;
+
+ result = MsgWaitForMultipleObjects(objects_nbr, (const HANDLE *)objects, EINA_FALSE,
+ timeout, QS_ALLINPUT);
+
+ if (readfds)
+ FD_ZERO(readfds);
+ if (writefds)
+ FD_ZERO(writefds);
+ if (exceptfds)
+ FD_ZERO(exceptfds);
+
+ /* The result tells us the type of event we have. */
+ if (result == WAIT_FAILED)
+ {
+ char *m;
+
+ m = evil_last_error_get();
+ ERR("%s", m);
+ free(m);
+ res = -1;
+ }
+ else if (result == WAIT_TIMEOUT)
+ {
+ /* ERR("time out\n"); */
+ res = 0;
+ }
+ else if (result == (WAIT_OBJECT_0 + objects_nbr))
+ {
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ res = 0;
+ }
+ else if ((result >= 0) && (result < WAIT_OBJECT_0 + events_nbr))
+ {
+ WSANETWORKEVENTS network_event;
+
+ WSAEnumNetworkEvents(sockets[result], objects[result], &network_event);
+
+ if ((network_event.lNetworkEvents & FD_READ) && readfds)
+ FD_SET(sockets[result], readfds);
+ if ((network_event.lNetworkEvents & FD_WRITE) && writefds)
+ FD_SET(sockets[result], writefds);
+ if ((network_event.lNetworkEvents & FD_OOB) && exceptfds)
+ FD_SET(sockets[result], exceptfds);
+
+ res = 1;
+ }
+ else if ((result >= (WAIT_OBJECT_0 + events_nbr)) &&
+ (result < (WAIT_OBJECT_0 + objects_nbr)))
+ {
+ if (!win32_handler_current)
+ {
+ /* regular main loop, start from head */
+ win32_handler_current = win32_handlers;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ win32_handler_current = (Ecore_Win32_Handler *)EINA_INLIST_GET(win32_handler_current)->next;
+ }
+
+ while (win32_handler_current)
+ {
+ wh = win32_handler_current;
+
+ if (objects[result - WAIT_OBJECT_0] == wh->h)
+ {
+ if (!wh->delete_me)
+ {
+ wh->references++;
+ if (!wh->func(wh->data, wh))
+ {
+ wh->delete_me = EINA_TRUE;
+ win32_handlers_delete_me = EINA_TRUE;
+ }
+ wh->references--;
+ }
+ }
+ if (win32_handler_current) /* may have changed in recursive main loops */
+ win32_handler_current = (Ecore_Win32_Handler *)EINA_INLIST_GET(win32_handler_current)->next;
+ }
+ res = 1;
+ }
+ else
+ {
+ ERR("unknown result...\n");
+ res = -1;
+ }
+
+ /* Remove event objects again */
+ for (i = 0; i < events_nbr; i++) WSACloseEvent(objects[i]);
+
+ return res;
+}
+
+#endif
diff --git a/src/lib/ecore/ecore_pipe.c b/src/lib/ecore/ecore_pipe.c
new file mode 100644
index 0000000000..c6962a5d58
--- /dev/null
+++ b/src/lib/ecore/ecore_pipe.c
@@ -0,0 +1,748 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <math.h>
+
+#ifdef HAVE_ISFINITE
+# define ECORE_FINITE(t) isfinite(t)
+#else
+# ifdef _MSC_VER
+# define ECORE_FINITE(t) _finite(t)
+# else
+# define ECORE_FINITE(t) finite(t)
+# endif
+#endif
+
+#define FIX_HZ 1
+
+#ifdef FIX_HZ
+# ifndef _MSC_VER
+# include <sys/param.h>
+# endif
+# ifndef HZ
+# define HZ 100
+# endif
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef HAVE_ESCAPE
+# include <Escape.h>
+#endif
+
+#ifdef HAVE_EXOTIC
+# include <Exotic.h>
+#endif
+
+/*
+ * On Windows, pipe() is implemented with sockets.
+ * Contrary to Linux, Windows uses different functions
+ * for sockets and fd's: write() is for fd's and send
+ * is for sockets. So I need to put some win32 code
+ * here. I can't think of a solution where the win32
+ * code is in Evil and not here.
+ */
+
+#ifdef _WIN32
+
+# include <winsock2.h>
+
+# define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0)
+# define pipe_read(fd, buffer, size) recv((fd), (char *)(buffer), size, 0)
+# define pipe_close(fd) closesocket(fd)
+# define PIPE_FD_INVALID INVALID_SOCKET
+# define PIPE_FD_ERROR SOCKET_ERROR
+
+#else
+
+# include <unistd.h>
+# include <fcntl.h>
+
+# define pipe_write(fd, buffer, size) write((fd), buffer, size)
+# define pipe_read(fd, buffer, size) read((fd), buffer, size)
+# define pipe_close(fd) close(fd)
+# define PIPE_FD_INVALID -1
+# define PIPE_FD_ERROR -1
+
+#endif /* ! _WIN32 */
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* How of then we should retry to write to the pipe */
+#define ECORE_PIPE_WRITE_RETRY 6
+
+struct _Ecore_Pipe
+{
+ ECORE_MAGIC;
+ int fd_read;
+ int fd_write;
+ Ecore_Fd_Handler *fd_handler;
+ const void *data;
+ Ecore_Pipe_Cb handler;
+ unsigned int len;
+ int handling;
+ size_t already_read;
+ void *passed_data;
+ int message;
+ Eina_Bool delete_me : 1;
+};
+GENERIC_ALLOC_SIZE_DECLARE(Ecore_Pipe);
+
+static Eina_Bool _ecore_pipe_read(void *data,
+ Ecore_Fd_Handler *fd_handler);
+
+/**
+ * @addtogroup Ecore_Pipe_Group
+ *
+ * @{
+ */
+
+/**
+ * Create two file descriptors (sockets on Windows). Add
+ * a callback that will be called when the file descriptor that
+ * is listened receives data. An event is also put in the event
+ * queue when data is received.
+ *
+ * @param handler The handler called when data is received.
+ * @param data Data to pass to @p handler when it is called.
+ * @return A newly created Ecore_Pipe object if successful.
+ * @c NULL otherwise.
+ */
+EAPI Ecore_Pipe *
+ecore_pipe_add(Ecore_Pipe_Cb handler,
+ const void *data)
+{
+ Ecore_Pipe *p;
+
+ _ecore_lock();
+ p = _ecore_pipe_add(handler, data);
+ _ecore_unlock();
+
+ return p;
+}
+
+/**
+ * Free an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object to be freed.
+ * @return The pointer to the private data
+ */
+EAPI void *
+ecore_pipe_del(Ecore_Pipe *p)
+{
+ void *r;
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+ r = _ecore_pipe_del(p);
+ _ecore_unlock();
+ return r;
+}
+
+/**
+ * Close the read end of an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object.
+ */
+EAPI void
+ecore_pipe_read_close(Ecore_Pipe *p)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
+ goto out;
+ }
+ if (p->fd_handler)
+ {
+ _ecore_main_fd_handler_del(p->fd_handler);
+ p->fd_handler = NULL;
+ }
+ if (p->fd_read != PIPE_FD_INVALID)
+ {
+ pipe_close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ }
+out:
+ _ecore_unlock();
+}
+
+/**
+ * Stop monitoring if necessary the pipe for reading. See ecore_pipe_thaw()
+ * for monitoring it again.
+ *
+ * @param p The Ecore_Pipe object.
+ * @since 1.1
+ */
+EAPI void
+ecore_pipe_freeze(Ecore_Pipe *p)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_freeze");
+ goto out;
+ }
+ if (p->fd_handler)
+ {
+ _ecore_main_fd_handler_del(p->fd_handler);
+ p->fd_handler = NULL;
+ }
+out:
+ _ecore_unlock();
+}
+
+/**
+ * Start monitoring again the pipe for reading. See ecore_pipe_freeze() for
+ * stopping the monitoring activity. This will not work if
+ * ecore_pipe_read_close() was previously called on the same pipe.
+ *
+ * @param p The Ecore_Pipe object.
+ * @since 1.1
+ */
+EAPI void
+ecore_pipe_thaw(Ecore_Pipe *p)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_thaw");
+ goto out;
+ }
+ if (!p->fd_handler && p->fd_read != PIPE_FD_INVALID)
+ {
+ p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
+ ECORE_FD_READ,
+ _ecore_pipe_read,
+ p,
+ NULL, NULL);
+ }
+out:
+ _ecore_unlock();
+}
+
+/**
+ * @brief Wait from another thread on the read side of a pipe.
+ *
+ * @param p The pipe to watch on.
+ * @param message_count The minimal number of message to wait before exiting.
+ * @param wait The amount of time in second to wait before exiting.
+ * @return the number of message catched during that wait call.
+ * @since 1.1
+ *
+ * Negative value for @p wait means infite wait.
+ */
+EAPI int
+ecore_pipe_wait(Ecore_Pipe *p,
+ int message_count,
+ double wait)
+{
+ int r;
+ _ecore_lock();
+ r = _ecore_pipe_wait(p, message_count, wait);
+ _ecore_unlock();
+ return r;
+}
+
+/**
+ * Close the write end of an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object.
+ */
+EAPI void
+ecore_pipe_write_close(Ecore_Pipe *p)
+{
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
+ goto out;
+ }
+ if (p->fd_write != PIPE_FD_INVALID)
+ {
+ pipe_close(p->fd_write);
+ p->fd_write = PIPE_FD_INVALID;
+ }
+out:
+ _ecore_unlock();
+}
+
+/**
+ * Write on the file descriptor the data passed as parameter.
+ *
+ * @param p The Ecore_Pipe object.
+ * @param buffer The data to write into the pipe.
+ * @param nbytes The size of the @p buffer in bytes
+ * @return @c EINA_TRUE on a successful write, @c EINA_FALSE on error.
+ */
+EAPI Eina_Bool
+ecore_pipe_write(Ecore_Pipe *p,
+ const void *buffer,
+ unsigned int nbytes)
+{
+ ssize_t ret;
+ size_t already_written = 0;
+ int retry = ECORE_PIPE_WRITE_RETRY;
+ Eina_Bool ok = EINA_FALSE;
+
+ _ecore_lock();
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write");
+ goto out;
+ }
+
+ if (p->delete_me) goto out;
+
+ if (p->fd_write == PIPE_FD_INVALID) goto out;
+
+ /* First write the len into the pipe */
+ do
+ {
+ ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes));
+ if (ret == sizeof(nbytes))
+ {
+ retry = ECORE_PIPE_WRITE_RETRY;
+ break;
+ }
+ else if (ret > 0)
+ {
+ /* XXX What should we do here? */
+ ERR("The length of the data was not written complete"
+ " to the pipe");
+ goto out;
+ }
+ else if (ret == PIPE_FD_ERROR && errno == EPIPE)
+ {
+ pipe_close(p->fd_write);
+ p->fd_write = PIPE_FD_INVALID;
+ goto out;
+ }
+ else if (ret == PIPE_FD_ERROR && errno == EINTR)
+ /* try it again */
+ ;
+ else
+ {
+ ERR("An unhandled error (ret: %zd errno: %d)"
+ "occurred while writing to the pipe the length",
+ ret, errno);
+ }
+ }
+ while (retry--);
+
+ if (retry != ECORE_PIPE_WRITE_RETRY) goto out;
+
+ /* and now pass the data to the pipe */
+ do
+ {
+ ret = pipe_write(p->fd_write,
+ ((unsigned char *)buffer) + already_written,
+ nbytes - already_written);
+
+ if (ret == (ssize_t)(nbytes - already_written))
+ {
+ ok = EINA_TRUE;
+ goto out;
+ }
+ else if (ret >= 0)
+ {
+ already_written -= ret;
+ continue;
+ }
+ else if (ret == PIPE_FD_ERROR && errno == EPIPE)
+ {
+ pipe_close(p->fd_write);
+ p->fd_write = PIPE_FD_INVALID;
+ goto out;
+ }
+ else if (ret == PIPE_FD_ERROR && errno == EINTR)
+ /* try it again */
+ ;
+ else
+ {
+ ERR("An unhandled error (ret: %zd errno: %d)"
+ "occurred while writing to the pipe the length",
+ ret, errno);
+ }
+ }
+ while (retry--);
+
+out:
+ _ecore_unlock();
+ return ok;
+}
+
+/**
+ * @}
+ */
+
+/* Private functions */
+Ecore_Pipe *
+_ecore_pipe_add(Ecore_Pipe_Cb handler,
+ const void *data)
+{
+ Ecore_Pipe *p = NULL;
+ int fds[2];
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ if (!handler) return NULL;
+
+ p = ecore_pipe_calloc(1);
+ if (!p) return NULL;
+
+ if (pipe(fds))
+ {
+ ecore_pipe_mp_free(p);
+ return NULL;
+ }
+
+ ECORE_MAGIC_SET(p, ECORE_MAGIC_PIPE);
+ p->fd_read = fds[0];
+ p->fd_write = fds[1];
+ p->handler = handler;
+ p->data = data;
+
+ fcntl(p->fd_read, F_SETFL, O_NONBLOCK);
+ p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
+ ECORE_FD_READ,
+ _ecore_pipe_read,
+ p,
+ NULL, NULL);
+
+ return p;
+}
+
+void *
+_ecore_pipe_del(Ecore_Pipe *p)
+{
+ void *data = NULL;
+
+ if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+ {
+ ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
+ return NULL;
+ }
+ p->delete_me = EINA_TRUE;
+ if (p->handling > 0) return (void *)p->data;
+ if (p->fd_handler) _ecore_main_fd_handler_del(p->fd_handler);
+ if (p->fd_read != PIPE_FD_INVALID) pipe_close(p->fd_read);
+ if (p->fd_write != PIPE_FD_INVALID) pipe_close(p->fd_write);
+ data = (void *)p->data;
+ ecore_pipe_mp_free(p);
+ return data;
+}
+
+int
+_ecore_pipe_wait(Ecore_Pipe *p,
+ int message_count,
+ double wait)
+{
+ struct timeval tv, *t;
+ fd_set rset;
+ double end = 0.0;
+ double timeout;
+ int ret;
+ int total = 0;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1);
+ if (p->fd_read == PIPE_FD_INVALID)
+ return -1;
+
+ FD_ZERO(&rset);
+ FD_SET(p->fd_read, &rset);
+
+ if (wait >= 0.0)
+ end = ecore_loop_time_get() + wait;
+ timeout = wait;
+
+ while (message_count > 0 && (timeout > 0.0 || wait <= 0.0))
+ {
+ if (wait >= 0.0)
+ {
+ /* finite() tests for NaN, too big, too small, and infinity. */
+ if ((!ECORE_FINITE(timeout)) || (timeout == 0.0))
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ else if (timeout > 0.0)
+ {
+ int sec, usec;
+#ifdef FIX_HZ
+ timeout += (0.5 / HZ);
+ sec = (int)timeout;
+ usec = (int)((timeout - (double)sec) * 1000000);
+#else
+ sec = (int)timeout;
+ usec = (int)((timeout - (double)sec) * 1000000);
+#endif
+ tv.tv_sec = sec;
+ tv.tv_usec = usec;
+ }
+ t = &tv;
+ }
+ else
+ {
+ t = NULL;
+ }
+
+ ret = main_loop_select(p->fd_read + 1, &rset, NULL, NULL, t);
+
+ if (ret > 0)
+ {
+ _ecore_pipe_read(p, NULL);
+ message_count -= p->message;
+ total += p->message;
+ p->message = 0;
+ }
+ else if (ret == 0)
+ {
+ break;
+ }
+ else if (errno != EINTR)
+ {
+ close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ break;
+ }
+
+ if (wait >= 0.0)
+ timeout = end - ecore_loop_time_get();
+ }
+
+ return total;
+}
+
+static void
+_ecore_pipe_unhandle(Ecore_Pipe *p)
+{
+ p->handling--;
+ if (p->delete_me)
+ {
+ _ecore_pipe_del(p);
+ }
+}
+
+static void
+_ecore_pipe_handler_call(Ecore_Pipe *p,
+ unsigned char *buf,
+ size_t len)
+{
+ void *data = (void*) p->data;
+ if (!p->delete_me)
+ {
+ _ecore_unlock();
+ p->handler(data, buf, len);
+ _ecore_lock();
+ }
+}
+
+static Eina_Bool
+_ecore_pipe_read(void *data,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Ecore_Pipe *p = (Ecore_Pipe *)data;
+ int i;
+
+ p->handling++;
+ for (i = 0; i < 16; i++)
+ {
+ ssize_t ret;
+
+ /* if we already have read some data we don't need to read the len
+ * but to finish the already started job
+ */
+ if (p->len == 0)
+ {
+ /* read the len of the passed data */
+ ret = pipe_read(p->fd_read, &p->len, sizeof(p->len));
+
+ /* catch the non error case first */
+ /* read amount ok - nothing more to do */
+ if (ret == sizeof(p->len))
+ ;
+ else if (ret > 0)
+ {
+ /* we got more data than we asked for - definite error */
+ ERR("Only read %i bytes from the pipe, although"
+ " we need to read %i bytes.",
+ (int)ret, (int)sizeof(p->len));
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ else if (ret == 0)
+ {
+ /* we got no data */
+ if (i == 0)
+ {
+ /* no data on first try through means an error */
+ _ecore_pipe_handler_call(p, NULL, 0);
+ if (p->passed_data) free(p->passed_data);
+ p->passed_data = NULL;
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ pipe_close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ p->fd_handler = NULL;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ else
+ {
+ /* no data after first loop try is ok */
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+ }
+#ifndef _WIN32
+ else if ((ret == PIPE_FD_ERROR) &&
+ ((errno == EINTR) || (errno == EAGAIN)))
+ {
+ return ECORE_CALLBACK_RENEW;
+ }
+ else
+ {
+ ERR("An unhandled error (ret: %i errno: %i [%s])"
+ "occurred while reading from the pipe the length",
+ (int)ret, errno, strerror(errno));
+ return ECORE_CALLBACK_RENEW;
+ }
+#else
+ else /* ret == PIPE_FD_ERROR is the only other case on Windows */
+ {
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ _ecore_pipe_handler_call(p, NULL, 0);
+ if (p->passed_data) free(p->passed_data);
+ p->passed_data = NULL;
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ pipe_close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ p->fd_handler = NULL;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+#endif
+ }
+
+ /* if somehow we got less than or equal to 0 we got an errnoneous
+ * messages so call callback with null and len we got. this case should
+ * never happen */
+ if (p->len == 0)
+ {
+ _ecore_pipe_handler_call(p, NULL, 0);
+ /* reset all values to 0 */
+ if (p->passed_data) free(p->passed_data);
+ p->passed_data = NULL;
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ /* we dont have a buffer to hold the data, so alloc it */
+ if (!p->passed_data)
+ {
+ p->passed_data = malloc(p->len);
+ /* alloc failed - error case */
+ if (!p->passed_data)
+ {
+ _ecore_pipe_handler_call(p, NULL, 0);
+ /* close the pipe */
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ pipe_close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ p->fd_handler = NULL;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+
+ /* and read the passed data */
+ ret = pipe_read(p->fd_read,
+ ((unsigned char *)p->passed_data) + p->already_read,
+ p->len - p->already_read);
+
+ /* catch the non error case first */
+ /* if we read enough data to finish the message/buffer */
+ if (ret == (ssize_t)(p->len - p->already_read))
+ {
+ _ecore_pipe_handler_call(p, p->passed_data, p->len);
+ free(p->passed_data);
+ /* reset all values to 0 */
+ p->passed_data = NULL;
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ }
+ else if (ret > 0)
+ {
+ /* more data left to read */
+ p->already_read += ret;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+ else if (ret == 0)
+ {
+ /* 0 bytes to read - could be more to read next select wake up */
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+#ifndef _WIN32
+ else if ((ret == PIPE_FD_ERROR) &&
+ ((errno == EINTR) || (errno == EAGAIN)))
+ {
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+ else
+ {
+ ERR("An unhandled error (ret: %zd errno: %d)"
+ "occurred while reading from the pipe the data",
+ ret, errno);
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+ }
+#else
+ else /* ret == PIPE_FD_ERROR is the only other case on Windows */
+ {
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ _ecore_pipe_handler_call(p, NULL, 0);
+ if (p->passed_data) free(p->passed_data);
+ p->passed_data = NULL;
+ p->already_read = 0;
+ p->len = 0;
+ p->message++;
+ pipe_close(p->fd_read);
+ p->fd_read = PIPE_FD_INVALID;
+ p->fd_handler = NULL;
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ else
+ break;
+ }
+#endif
+ }
+
+ _ecore_pipe_unhandle(p);
+ return ECORE_CALLBACK_RENEW;
+}
+
diff --git a/src/lib/ecore/ecore_poll.c b/src/lib/ecore/ecore_poll.c
new file mode 100644
index 0000000000..28be53857c
--- /dev/null
+++ b/src/lib/ecore/ecore_poll.c
@@ -0,0 +1,490 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_POLLER_CLASS
+
+#define MY_CLASS_NAME "ecore_poller"
+
+EAPI Eo_Op ECORE_POLLER_BASE_ID = EO_NOOP;
+
+#define ECORE_POLLER_CHECK(obj) \
+ if (!eo_isa((obj), ECORE_POLLER_CLASS)) \
+ return
+
+struct _Ecore_Poller_Private_Data
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ Ecore_Poller *obj;
+ int ibit;
+ unsigned char delete_me : 1;
+ Ecore_Task_Cb func;
+ void *data;
+};
+
+typedef struct _Ecore_Poller_Private_Data Ecore_Poller_Private_Data;
+
+static Ecore_Timer *timer = NULL;
+static int min_interval = -1;
+static int interval_incr = 0;
+static int at_tick = 0;
+static int just_added_poller = 0;
+static int poller_delete_count = 0;
+static int poller_walking = 0;
+static double poll_interval = 0.125;
+static double poll_cur_interval = 0.0;
+static double last_tick = 0.0;
+static Ecore_Poller_Private_Data *pollers[16] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+static unsigned short poller_counters[16] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void _ecore_poller_next_tick_eval(void);
+static Eina_Bool _ecore_poller_cb_timer(void *data);
+
+static void
+_ecore_poller_next_tick_eval(void)
+{
+ int i;
+ double interval;
+
+ min_interval = -1;
+ for (i = 0; i < 15; i++)
+ {
+ if (pollers[i])
+ {
+ min_interval = i;
+ break;
+ }
+ }
+ if (min_interval < 0)
+ {
+ /* no pollers */
+ if (timer)
+ {
+ ecore_timer_del(timer);
+ timer = NULL;
+ }
+ return;
+ }
+ interval_incr = (1 << min_interval);
+ interval = interval_incr * poll_interval;
+ /* we are at the tick callback - so no need to do inter-tick adjustments
+ * so we can fasttrack this as t -= last_tick in theory is 0.0 (though
+ * in practice it will be a very very very small value. also the tick
+ * callback will adjust the timer interval at the end anyway */
+ if (at_tick)
+ {
+ if (!timer)
+ timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
+ }
+ else
+ {
+ double t;
+
+ if (!timer)
+ timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
+ else
+ {
+ t = ecore_time_get();
+ if (interval != poll_cur_interval)
+ {
+ t -= last_tick; /* time since we last ticked */
+ /* delete the timer and reset it to tick off in the new
+ * time interval. at the tick this will be adjusted */
+ ecore_timer_del(timer);
+ timer = ecore_timer_add(interval - t,
+ _ecore_poller_cb_timer, NULL);
+ }
+ }
+ }
+ poll_cur_interval = interval;
+}
+
+static Eina_Bool
+_ecore_poller_cb_timer(void *data EINA_UNUSED)
+{
+ int i;
+ Ecore_Poller_Private_Data *poller, *l;
+ int changes = 0;
+
+ at_tick++;
+ last_tick = ecore_time_get();
+ /* we have 16 counters - each increments every time the poller counter
+ * "ticks". it increments by the minimum interval (which can be 1, 2, 4,
+ * 7, 16 etc. up to 32768) */
+ for (i = 0; i < 15; i++)
+ {
+ poller_counters[i] += interval_incr;
+ /* wrap back to 0 if we exceed out loop count for the counter */
+ if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0;
+ }
+
+ just_added_poller = 0;
+ /* walk the pollers now */
+ poller_walking++;
+ for (i = 0; i < 15; i++)
+ {
+ /* if the counter is @ 0 - this means that counter "went off" this
+ * tick interval, so run all pollers hooked to that counter */
+ if (poller_counters[i] == 0)
+ {
+ EINA_INLIST_FOREACH(pollers[i], poller)
+ {
+ if (!poller->delete_me)
+ {
+ if (!poller->func(poller->data))
+ {
+ if (!poller->delete_me)
+ {
+ poller->delete_me = 1;
+ poller_delete_count++;
+ }
+ }
+ }
+ }
+ }
+ }
+ poller_walking--;
+
+ /* handle deletes afterwards */
+ if (poller_delete_count > 0)
+ {
+ /* FIXME: walk all pollers and remove deleted ones */
+ for (i = 0; i < 15; i++)
+ {
+ for (l = pollers[i]; l; )
+ {
+ poller = l;
+ l = (Ecore_Poller_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (poller->delete_me)
+ {
+ pollers[i] = (Ecore_Poller_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(poller));
+
+ eo_parent_set(poller->obj, NULL);
+ if (eo_destructed_is(poller->obj))
+ eo_manual_free(poller->obj);
+ else
+ eo_manual_free_set(poller->obj, EINA_FALSE);
+
+ poller_delete_count--;
+ changes++;
+ if (poller_delete_count <= 0) break;
+ }
+ }
+ if (poller_delete_count <= 0) break;
+ }
+ }
+ /* if we deleted or added any pollers, then we need to re-evaluate our
+ * minimum poll interval */
+ if ((changes > 0) || (just_added_poller > 0))
+ _ecore_poller_next_tick_eval();
+
+ just_added_poller = 0;
+ poller_delete_count = 0;
+
+ at_tick--;
+
+ /* if the timer was deleted then there is no point returning 1 - ambiguous
+ * if we do as it implies keep running me" but we have been deleted
+ * anyway */
+ if (!timer) return ECORE_CALLBACK_CANCEL;
+
+ /* adjust interval */
+ ecore_timer_interval_set(timer, poll_cur_interval);
+ return ECORE_CALLBACK_RENEW;
+}
+
+EAPI void
+ecore_poller_poll_interval_set(Ecore_Poller_Type type EINA_UNUSED,
+ double poll_time)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ if (poll_time < 0.0)
+ {
+ ERR("Poll time %f less than zero, ignored", poll_time);
+ return;
+ }
+
+ poll_interval = poll_time;
+ _ecore_poller_next_tick_eval();
+}
+
+EAPI double
+ecore_poller_poll_interval_get(Ecore_Poller_Type type EINA_UNUSED)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
+ return poll_interval;
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+EAPI Ecore_Poller *
+ecore_poller_add(Ecore_Poller_Type type EINA_UNUSED,
+ int interval,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Poller *poller;
+ poller = eo_add_custom(MY_CLASS, _ecore_parent,
+ ecore_poller_constructor(type, interval, func, data));
+ eo_unref(poller);
+ return poller;
+}
+
+static void
+_poller_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ Ecore_Poller_Type type = va_arg(*list, Ecore_Poller_Type);
+ (void)type;
+ int interval = va_arg(*list, int);
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+
+
+ Ecore_Poller_Private_Data *poller = _pd;
+ poller->obj = obj;
+
+ int ibit;
+
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ }
+
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return;
+ }
+
+ /* interval MUST be a power of 2, so enforce it */
+ if (interval < 1) interval = 1;
+ ibit = -1;
+ while (interval != 0)
+ {
+ ibit++;
+ interval >>= 1;
+ }
+ /* only allow up to 32768 - i.e. ibit == 15, so limit it */
+ if (ibit > 15) ibit = 15;
+
+ poller->ibit = ibit;
+ poller->func = func;
+ poller->data = (void *)data;
+ pollers[poller->ibit] = (Ecore_Poller_Private_Data *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
+ if (poller_walking)
+ just_added_poller++;
+ else
+ _ecore_poller_next_tick_eval();
+}
+
+EAPI Eina_Bool
+ecore_poller_poller_interval_set(Ecore_Poller *obj,
+ int interval)
+{
+ Eina_Bool ret;
+ ECORE_POLLER_CHECK(obj) EINA_FALSE;
+ eo_do(obj, ecore_poller_interval_set(interval, &ret));
+ return ret;
+}
+
+static void
+_poller_interval_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ int interval = va_arg(*list, int);
+ Eina_Bool *ret = va_arg(*list, Eina_Bool *);
+ Eina_Bool int_ret;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ int ibit;
+
+ Ecore_Poller_Private_Data *poller = _pd;
+
+ /* interval MUST be a power of 2, so enforce it */
+ if (interval < 1) interval = 1;
+ ibit = -1;
+ while (interval != 0)
+ {
+ ibit++;
+ interval >>= 1;
+ }
+ /* only allow up to 32768 - i.e. ibit == 15, so limit it */
+ if (ibit > 15) ibit = 15;
+ /* if interval specified is the same as interval set, return true without wasting time */
+ if (poller->ibit == ibit)
+ {
+ int_ret = EINA_TRUE;
+ goto end;
+ }
+
+ pollers[poller->ibit] = (Ecore_Poller_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
+ poller->ibit = ibit;
+ pollers[poller->ibit] = (Ecore_Poller_Private_Data *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
+ if (poller_walking)
+ just_added_poller++;
+ else
+ _ecore_poller_next_tick_eval();
+
+ int_ret = EINA_TRUE;
+
+end:
+ if (ret) *ret = int_ret;
+}
+
+EAPI int
+ecore_poller_poller_interval_get(Ecore_Poller *obj)
+{
+ int ret;
+ ECORE_POLLER_CHECK(obj) EINA_FALSE;
+ eo_do(obj, ecore_poller_interval_get(&ret));
+ return ret;
+}
+
+static void
+_poller_interval_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ int *ret = va_arg(*list, int *);
+ *ret =0;
+
+ int ibit, interval = 1;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ Ecore_Poller_Private_Data *poller = _pd;
+
+ ibit = poller->ibit;
+ while (ibit != 0)
+ {
+ ibit--;
+ interval <<= 1;
+ }
+ *ret = interval;
+}
+
+EAPI void *
+ecore_poller_del(Ecore_Poller *obj)
+{
+ void *data;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ Ecore_Poller_Private_Data *poller = eo_data_get(obj, MY_CLASS);
+ /* we are walking the poller list - a bad idea to remove from it while
+ * walking it, so just flag it as delete_me and come back to it after
+ * the loop has finished */
+ if (poller_walking > 0)
+ {
+ poller_delete_count++;
+ poller->delete_me = 1;
+ return poller->data;
+ }
+ /* not in loop so safe - delete immediately */
+ data = poller->data;
+ pollers[poller->ibit] = (Ecore_Poller_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller));
+
+ eo_parent_set(poller->obj, NULL);
+ if (eo_destructed_is(poller->obj))
+ eo_manual_free(obj);
+ else
+ eo_manual_free_set(obj, EINA_FALSE);
+
+ _ecore_poller_next_tick_eval();
+ return data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Poller_Private_Data *pd = _pd;
+
+ if (!pd->delete_me)
+ {
+ pd->delete_me = 1;
+ poller_delete_count++;
+ }
+
+ eo_do_super(obj, eo_destructor());
+}
+
+/**
+ * @}
+ */
+
+void
+_ecore_poller_shutdown(void)
+{
+ int i;
+ Ecore_Poller_Private_Data *poller;
+
+ for (i = 0; i < 15; i++)
+ {
+ while ((poller = pollers[i]))
+ {
+ pollers[i] = (Ecore_Poller_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(pollers[i]));
+ eo_parent_set(poller->obj, NULL);
+ if (eo_destructed_is(poller->obj))
+ eo_manual_free(poller->obj);
+ else
+ eo_manual_free_set(poller->obj, EINA_FALSE);
+ }
+ }
+}
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+ EO_OP_FUNC(ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_CONSTRUCTOR), _poller_constructor),
+ EO_OP_FUNC(ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_INTERVAL_SET), _poller_interval_set),
+ EO_OP_FUNC(ECORE_POLLER_ID(ECORE_POLLER_SUB_ID_INTERVAL_GET), _poller_interval_get),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_POLLER_SUB_ID_CONSTRUCTOR, "Add an idle enterer handler."),
+ EO_OP_DESCRIPTION(ECORE_POLLER_SUB_ID_INTERVAL_SET, "Changes the polling interval rate of poller."),
+ EO_OP_DESCRIPTION(ECORE_POLLER_SUB_ID_INTERVAL_GET, "Gets the polling interval rate of poller"),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_POLLER_BASE_ID, op_desc, ECORE_POLLER_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Poller_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_poller_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h
new file mode 100644
index 0000000000..f0add822fe
--- /dev/null
+++ b/src/lib/ecore/ecore_private.h
@@ -0,0 +1,398 @@
+#ifndef _ECORE_PRIVATE_H
+#define _ECORE_PRIVATE_H
+
+#include <assert.h>
+
+extern int _ecore_log_dom;
+#ifdef _ECORE_DEFAULT_LOG_DOM
+# undef _ECORE_DEFAULT_LOG_DOM
+#endif
+#define _ECORE_DEFAULT_LOG_DOM _ecore_log_dom
+
+#ifdef ECORE_DEFAULT_LOG_COLOR
+# undef ECORE_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef MIN
+# define MIN(x, y) (((x) > (y)) ? (y) : (x))
+#endif
+
+#ifndef MAX
+# define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef ABS
+# define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+#ifndef CLAMP
+# define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x)))
+#endif
+
+#define EVAS_FRAME_QUEUING 1 /* for test */
+
+#define READBUFSIZ 65536
+
+#define ECORE_MAGIC_NONE 0x1234fedc
+#define ECORE_MAGIC_EXE 0xf7e812f5
+#define ECORE_MAGIC_TIMER 0xf7d713f4
+#define ECORE_MAGIC_IDLER 0xf7c614f3
+#define ECORE_MAGIC_IDLE_ENTERER 0xf7b515f2
+#define ECORE_MAGIC_IDLE_EXITER 0xf7601afd
+#define ECORE_MAGIC_FD_HANDLER 0xf7a416f1
+#define ECORE_MAGIC_EVENT_HANDLER 0xf79317f0
+#define ECORE_MAGIC_EVENT_FILTER 0xf78218ff
+#define ECORE_MAGIC_EVENT 0xf77119fe
+#define ECORE_MAGIC_ANIMATOR 0xf7643ea5
+#define ECORE_MAGIC_POLLER 0xf7568127
+#define ECORE_MAGIC_PIPE 0xf7458226
+#define ECORE_MAGIC_WIN32_HANDLER 0xf7e8f1a3
+#define ECORE_MAGIC_JOB 0x76543210
+
+typedef unsigned int Ecore_Magic;
+#define ECORE_MAGIC Ecore_Magic __magic
+
+#define ECORE_MAGIC_SET(d, m) (d)->__magic = (m)
+#define ECORE_MAGIC_CHECK(d, m) ((d) && ((d)->__magic == (m)))
+#define ECORE_MAGIC_FAIL(d, m, fn) _ecore_magic_fail((d), (d) ? (d)->__magic : 0, (m), (fn));
+
+/* undef the following, we want our version */
+#undef FREE
+#define FREE(ptr) free(ptr); ptr = NULL;
+
+#undef IF_FREE
+#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL;
+
+#undef IF_FN_DEL
+#define IF_FN_DEL(_fn, ptr) if (ptr) { _fn(ptr); ptr = NULL; }
+
+EAPI void
+ecore_print_warning(const char *function,
+ const char *sparam);
+
+/* convenience macros for checking pointer parameters for non-NULL */
+#undef CHECK_PARAM_POINTER_RETURN
+#define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \
+ if (!(param)) \
+ { \
+ ecore_print_warning(__FUNCTION__, sparam); \
+ return ret; \
+ }
+
+#undef CHECK_PARAM_POINTER
+#define CHECK_PARAM_POINTER(sparam, param) \
+ if (!(param)) \
+ { \
+ ecore_print_warning(__FUNCTION__, sparam); \
+ return; \
+ }
+
+EAPI void _ecore_magic_fail(const void *d,
+ Ecore_Magic m,
+ Ecore_Magic req_m,
+ const char *fname);
+
+void _ecore_time_init(void);
+
+Ecore_Timer *_ecore_timer_loop_add(double in,
+ Ecore_Task_Cb func,
+ const void *data);
+void *_ecore_timer_del(Ecore_Timer *timer);
+void _ecore_timer_delay(Ecore_Timer *timer,
+ double add);
+void _ecore_timer_shutdown(void);
+void _ecore_timer_cleanup(void);
+void _ecore_timer_enable_new(void);
+double _ecore_timer_next_get(void);
+void _ecore_timer_expired_timers_call(double when);
+int _ecore_timers_exists(void);
+
+int _ecore_timer_expired_call(double when);
+
+void _ecore_idler_shutdown(void);
+int _ecore_idler_all_call(void);
+int _ecore_idler_exist(void);
+
+void _ecore_idle_enterer_shutdown(void);
+void _ecore_idle_enterer_call(void);
+int _ecore_idle_enterer_exist(void);
+
+void _ecore_idle_exiter_shutdown(void);
+void _ecore_idle_exiter_call(void);
+int _ecore_idle_exiter_exist(void);
+
+void _ecore_event_shutdown(void);
+int _ecore_event_exist(void);
+Ecore_Event *_ecore_event_add(int type,
+ void *ev,
+ Ecore_End_Cb func_free,
+ void *data);
+void _ecore_event_call(void);
+void *_ecore_event_handler_del(Ecore_Event_Handler *event_handler);
+
+Ecore_Timer *_ecore_exe_doomsday_clock_get(Ecore_Exe *exe);
+void _ecore_exe_doomsday_clock_set(Ecore_Exe *exe,
+ Ecore_Timer *dc);
+
+void *_ecore_event_signal_user_new(void);
+void *_ecore_event_signal_hup_new(void);
+void *_ecore_event_signal_exit_new(void);
+void *_ecore_event_signal_power_new(void);
+void *_ecore_event_signal_realtime_new(void);
+
+Ecore_Pipe *_ecore_pipe_add(Ecore_Pipe_Cb handler,
+ const void *data);
+int _ecore_pipe_wait(Ecore_Pipe *p,
+ int message_count,
+ double wait);
+void *_ecore_pipe_del(Ecore_Pipe *p);
+
+Ecore_Fd_Handler *
+ _ecore_main_fd_handler_add(int fd,
+ Ecore_Fd_Handler_Flags flags,
+ Ecore_Fd_Cb func,
+ const void *data,
+ Ecore_Fd_Cb buf_func,
+ const void *buf_data);
+void *_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler);
+
+void _ecore_main_shutdown(void);
+
+#if defined (_WIN32) || defined (__lv2ppu__) || defined (HAVE_EXOTIC)
+static inline void _ecore_signal_shutdown(void) { }
+
+static inline void _ecore_signal_init(void) { }
+
+static inline void _ecore_signal_received_process(void) { }
+
+static inline int _ecore_signal_count_get(void) { return 0; }
+
+static inline void _ecore_signal_call(void) { }
+
+#else
+void _ecore_signal_shutdown(void);
+void _ecore_signal_init(void);
+void _ecore_signal_received_process(void);
+int _ecore_signal_count_get(void);
+void _ecore_signal_call(void);
+#endif
+
+void _ecore_exe_init(void);
+void _ecore_exe_shutdown(void);
+#ifndef _WIN32
+Ecore_Exe *_ecore_exe_find(pid_t pid);
+void *_ecore_exe_event_del_new(void);
+void _ecore_exe_event_del_free(void *data,
+ void *ev);
+#endif
+
+void _ecore_animator_shutdown(void);
+
+void _ecore_poller_shutdown(void);
+
+void _ecore_fps_debug_init(void);
+void _ecore_fps_debug_shutdown(void);
+void _ecore_fps_debug_runtime_add(double t);
+
+void _ecore_thread_init(void);
+void _ecore_thread_shutdown(void);
+
+void _ecore_glib_init(void);
+void _ecore_glib_shutdown(void);
+
+void _ecore_job_init(void);
+void _ecore_job_shutdown(void);
+
+void _ecore_main_loop_init(void);
+void _ecore_main_loop_shutdown(void);
+
+void _ecore_throttle(void);
+
+void _ecore_main_call_flush(void);
+
+extern int _ecore_main_lock_count;
+extern Eina_Lock _ecore_main_loop_lock;
+
+static inline void
+_ecore_lock(void)
+{
+#ifdef HAVE_THREAD_SAFETY
+ eina_lock_take(&_ecore_main_loop_lock);
+#else
+ /* at least check we're not being called from a thread */
+ EINA_MAIN_LOOP_CHECK_RETURN;
+#endif
+ _ecore_main_lock_count++;
+ /* assert(_ecore_main_lock_count == 1); */
+}
+
+static inline void
+_ecore_unlock(void)
+{
+ _ecore_main_lock_count--;
+ /* assert(_ecore_main_lock_count == 0); */
+#ifdef HAVE_THREAD_SAFETY
+ eina_lock_release(&_ecore_main_loop_lock);
+#endif
+}
+
+/*
+ * Callback wrappers all assume that ecore _ecore_lock has been called
+ */
+static inline Eina_Bool
+_ecore_call_task_cb(Ecore_Task_Cb func,
+ void *data)
+{
+ Eina_Bool r;
+
+ _ecore_unlock();
+ r = func(data);
+ _ecore_lock();
+
+ return r;
+}
+
+static inline void *
+_ecore_call_data_cb(Ecore_Data_Cb func,
+ void *data)
+{
+ void *r;
+
+ _ecore_unlock();
+ r = func(data);
+ _ecore_lock();
+
+ return r;
+}
+
+static inline void
+_ecore_call_end_cb(Ecore_End_Cb func,
+ void *user_data,
+ void *func_data)
+{
+ _ecore_unlock();
+ func(user_data, func_data);
+ _ecore_lock();
+}
+
+static inline Eina_Bool
+_ecore_call_filter_cb(Ecore_Filter_Cb func,
+ void *data,
+ void *loop_data,
+ int type,
+ void *event)
+{
+ Eina_Bool r;
+
+ _ecore_unlock();
+ r = func(data, loop_data, type, event);
+ _ecore_lock();
+
+ return r;
+}
+
+static inline Eina_Bool
+_ecore_call_handler_cb(Ecore_Event_Handler_Cb func,
+ void *data,
+ int type,
+ void *event)
+{
+ Eina_Bool r;
+
+ _ecore_unlock();
+ r = func(data, type, event);
+ _ecore_lock();
+
+ return r;
+}
+
+static inline void
+_ecore_call_prep_cb(Ecore_Fd_Prep_Cb func,
+ void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ _ecore_unlock();
+ func(data, fd_handler);
+ _ecore_lock();
+}
+
+static inline Eina_Bool
+_ecore_call_fd_cb(Ecore_Fd_Cb func,
+ void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ Eina_Bool r;
+
+ _ecore_unlock();
+ r = func(data, fd_handler);
+ _ecore_lock();
+
+ return r;
+}
+
+extern int _ecore_fps_debug;
+extern double _ecore_time_loop_time;
+extern Eina_Bool _ecore_glib_always_integrate;
+extern Ecore_Select_Function main_loop_select;
+
+Eina_Bool ecore_mempool_init(void);
+void ecore_mempool_shutdown(void);
+#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \
+ TYPE *Type##_calloc(unsigned int); \
+ void Type##_mp_free(TYPE *e);
+#define GENERIC_ALLOC_SIZE_DECLARE(TYPE) \
+ size_t _ecore_sizeof_##TYPE = sizeof (TYPE);
+
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Animator, ecore_animator);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Event_Handler, ecore_event_handler);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Event_Filter, ecore_event_filter);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Event, ecore_event);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Idle_Exiter, ecore_idle_exiter);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Idle_Enterer, ecore_idle_enterer);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Idler, ecore_idler);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Job, ecore_job);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Timer, ecore_timer);
+//GENERIC_ALLOC_FREE_HEADER(Ecore_Poller, ecore_poller);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Pipe, ecore_pipe);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Fd_Handler, ecore_fd_handler);
+#ifdef _WIN32
+GENERIC_ALLOC_FREE_HEADER(Ecore_Win32_Handler, ecore_win32_handler);
+#endif
+
+#undef GENERIC_ALLOC_FREE_HEADER
+
+extern Eo *_ecore_parent;
+#define ECORE_PARENT_CLASS ecore_parent_class_get()
+const Eo_Class *ecore_parent_class_get(void) EINA_CONST;
+
+#endif
diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c
new file mode 100644
index 0000000000..8114f72b09
--- /dev/null
+++ b/src/lib/ecore/ecore_signal.c
@@ -0,0 +1,594 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* make mono happy - this is evil though... */
+#undef SIGPWR
+/* valgrind in some versions/setups uses SIGRT's... hmmm */
+
+typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo);
+
+static void _ecore_signal_callback_set(int sig,
+ Signal_Handler func);
+static void _ecore_signal_callback_ignore(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigchld(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigusr1(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigusr2(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sighup(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigquit(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigint(int sig,
+ siginfo_t *si,
+ void *foo);
+static void _ecore_signal_callback_sigterm(int sig,
+ siginfo_t *si,
+ void *foo);
+#ifdef SIGPWR
+static void _ecore_signal_callback_sigpwr(int sig,
+ siginfo_t *si,
+ void *foo);
+#endif
+
+static Eina_Bool _ecore_signal_exe_exit_delay(void *data);
+
+//#define MAXSIGQ 256 // 32k
+#define MAXSIGQ 64 // 8k
+
+static volatile sig_atomic_t sig_count = 0;
+static volatile sig_atomic_t sigchld_count = 0;
+static volatile sig_atomic_t sigusr1_count = 0;
+static volatile sig_atomic_t sigusr2_count = 0;
+static volatile sig_atomic_t sighup_count = 0;
+static volatile sig_atomic_t sigquit_count = 0;
+static volatile sig_atomic_t sigint_count = 0;
+static volatile sig_atomic_t sigterm_count = 0;
+#ifdef SIGPWR
+static volatile sig_atomic_t sigpwr_count = 0;
+#endif
+
+static volatile siginfo_t sigchld_info[MAXSIGQ];
+static volatile siginfo_t sigusr1_info[MAXSIGQ];
+static volatile siginfo_t sigusr2_info[MAXSIGQ];
+static volatile siginfo_t sighup_info[MAXSIGQ];
+static volatile siginfo_t sigquit_info[MAXSIGQ];
+static volatile siginfo_t sigint_info[MAXSIGQ];
+static volatile siginfo_t sigterm_info[MAXSIGQ];
+#ifdef SIGPWR
+static volatile siginfo_t sigpwr_info[MAXSIGQ];
+#endif
+
+void
+_ecore_signal_shutdown(void)
+{
+ _ecore_signal_callback_set(SIGPIPE, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGALRM, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGCHLD, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGUSR1, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGUSR2, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGHUP, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGQUIT, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGINT, (Signal_Handler)SIG_DFL);
+ _ecore_signal_callback_set(SIGTERM, (Signal_Handler)SIG_DFL);
+#ifdef SIGPWR
+ _ecore_signal_callback_set(SIGPWR, (Signal_Handler)SIG_DFL);
+ sigpwr_count = 0;
+#endif
+ sigchld_count = 0;
+ sigusr1_count = 0;
+ sigusr2_count = 0;
+ sighup_count = 0;
+ sigquit_count = 0;
+ sigint_count = 0;
+ sigterm_count = 0;
+ sig_count = 0;
+}
+
+void
+_ecore_signal_init(void)
+{
+ _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback_ignore);
+ _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback_ignore);
+ _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback_sigchld);
+ _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback_sigusr1);
+ _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback_sigusr2);
+ _ecore_signal_callback_set(SIGHUP, _ecore_signal_callback_sighup);
+ _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback_sigquit);
+ _ecore_signal_callback_set(SIGINT, _ecore_signal_callback_sigint);
+ _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback_sigterm);
+#ifdef SIGPWR
+ _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback_sigpwr);
+#endif
+}
+
+void
+_ecore_signal_received_process(void)
+{
+ while (_ecore_signal_count_get()) _ecore_signal_call();
+}
+
+int
+_ecore_signal_count_get(void)
+{
+ return sig_count;
+}
+
+static void
+_ecore_signal_generic_free(void *data EINA_UNUSED,
+ void *event)
+{
+ free(event);
+}
+
+void
+_ecore_signal_call(void)
+{
+ volatile sig_atomic_t n;
+ sigset_t oldset, newset;
+ int tot;
+
+ if (sig_count == 0) return;
+ sigemptyset(&newset);
+ sigaddset(&newset, SIGPIPE);
+ sigaddset(&newset, SIGALRM);
+ sigaddset(&newset, SIGCHLD);
+ sigaddset(&newset, SIGUSR1);
+ sigaddset(&newset, SIGUSR2);
+ sigaddset(&newset, SIGHUP);
+ sigaddset(&newset, SIGQUIT);
+ sigaddset(&newset, SIGINT);
+ sigaddset(&newset, SIGTERM);
+#ifdef SIGPWR
+ sigaddset(&newset, SIGPWR);
+#endif
+ sigprocmask(SIG_BLOCK, &newset, &oldset);
+ if (sigchld_count > MAXSIGQ)
+ WRN("%i SIGCHLD in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigchld_count, MAXSIGQ);
+ tot = sigchld_count + sigusr1_count + sigusr2_count +
+ sighup_count + sigquit_count + sigint_count + sigterm_count
+#ifdef SIGPWR
+ + sigpwr_count
+#endif
+ ;
+
+ if (sig_count != tot)
+ {
+ ERR("sig_count (%i) != actual totals (%i) ", sig_count, tot);
+ sig_count = tot;
+ }
+
+ for (n = 0; n < sigchld_count; n++)
+ {
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ Ecore_Exe_Event_Del *e;
+
+ /* FIXME: If this process is set respawn, respawn with a suitable backoff
+ * period for those that need too much respawning.
+ */
+ e = _ecore_exe_event_del_new();
+ if (e)
+ {
+ if (WIFEXITED(status))
+ {
+ e->exit_code = WEXITSTATUS(status);
+ e->exited = 1;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ e->exit_signal = WTERMSIG(status);
+ e->signalled = 1;
+ }
+ e->pid = pid;
+ e->exe = _ecore_exe_find(pid);
+
+ if ((n < MAXSIGQ) && (sigchld_info[n].si_signo))
+ e->data = sigchld_info[n]; /* No need to clone this. */
+
+ if ((e->exe) && (ecore_exe_flags_get(e->exe) & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR)))
+ {
+ /* We want to report the Last Words of the exe, so delay this event.
+ * This is twice as relevant for stderr.
+ * There are three possibilities here -
+ * 1 There are no Last Words.
+ * 2 There are Last Words, they are not ready to be read.
+ * 3 There are Last Words, they are ready to be read.
+ *
+ * For 1 we don't want to delay, for 3 we want to delay.
+ * 2 is the problem. If we check for data now and there
+ * is none, then there is no way to differentiate 1 and 2.
+ * If we don't delay, we may loose data, but if we do delay,
+ * there may not be data and the exit event never gets sent.
+ *
+ * Any way you look at it, there has to be some time passed
+ * before the exit event gets sent. So the strategy here is
+ * to setup a timer event that will send the exit event after
+ * an arbitrary, but brief, time.
+ *
+ * This is probably paranoid, for the less paraniod, we could
+ * check to see for Last Words, and only delay if there are any.
+ * This has it's own set of problems.
+ */
+ Ecore_Timer *doomsday_clock;
+
+ doomsday_clock = _ecore_exe_doomsday_clock_get(e->exe);
+ IF_FN_DEL(ecore_timer_del, doomsday_clock);
+ _ecore_unlock();
+ doomsday_clock = ecore_timer_add
+ (0.1, _ecore_signal_exe_exit_delay, e);
+ _ecore_lock();
+ _ecore_exe_doomsday_clock_set(e->exe, doomsday_clock);
+ }
+ else
+ {
+ _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
+ _ecore_exe_event_del_free, NULL);
+ }
+ }
+ }
+ sig_count--;
+ }
+ sigchld_count = 0;
+
+ if (sigusr1_count > MAXSIGQ)
+ WRN("%i SIGUSR1 in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigusr1_count, MAXSIGQ);
+ for (n = 0; n < sigusr1_count; n++)
+ {
+ Ecore_Event_Signal_User *e;
+
+ e = _ecore_event_signal_user_new();
+ if (e)
+ {
+ e->number = 1;
+
+ if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo))
+ e->data = sigusr1_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigusr1_count = 0;
+
+ if (sigusr2_count > MAXSIGQ)
+ WRN("%i SIGUSR2 in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigusr2_count, MAXSIGQ);
+ for (n = 0; n < sigusr2_count; n++)
+ {
+ Ecore_Event_Signal_User *e;
+
+ e = _ecore_event_signal_user_new();
+ if (e)
+ {
+ e->number = 2;
+
+ if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo))
+ e->data = sigusr2_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigusr2_count = 0;
+
+ if (sighup_count > MAXSIGQ)
+ WRN("%i SIGHUP in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sighup_count, MAXSIGQ);
+ for (n = 0; n < sighup_count; n++)
+ {
+ Ecore_Event_Signal_Hup *e;
+
+ e = _ecore_event_signal_hup_new();
+ if (e)
+ {
+ if ((n < MAXSIGQ) && (sighup_info[n].si_signo))
+ e->data = sighup_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sighup_count = 0;
+
+ if (sigquit_count > MAXSIGQ)
+ WRN("%i SIGQUIT in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigquit_count, MAXSIGQ);
+ for (n = 0; n < sigquit_count; n++)
+ {
+ Ecore_Event_Signal_Exit *e;
+
+ e = _ecore_event_signal_exit_new();
+ if (e)
+ {
+ e->quit = 1;
+
+ if ((n < MAXSIGQ) && (sigquit_info[n].si_signo))
+ e->data = sigquit_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigquit_count = 0;
+
+ if (sigint_count > MAXSIGQ)
+ WRN("%i SIGINT in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigint_count, MAXSIGQ);
+ for (n = 0; n < sigint_count; n++)
+ {
+ Ecore_Event_Signal_Exit *e;
+
+ e = _ecore_event_signal_exit_new();
+ if (e)
+ {
+ e->interrupt = 1;
+
+ if ((n < MAXSIGQ) && (sigint_info[n].si_signo))
+ e->data = sigint_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigint_count = 0;
+
+ if (sigterm_count > MAXSIGQ)
+ WRN("%i SIGTERM in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigterm_count, MAXSIGQ);
+ for (n = 0; n < sigterm_count; n++)
+ {
+ Ecore_Event_Signal_Exit *e;
+
+ e = _ecore_event_signal_exit_new();
+ if (e)
+ {
+ e->terminate = 1;
+
+ if ((n < MAXSIGQ) && (sigterm_info[n].si_signo))
+ e->data = sigterm_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigterm_count = 0;
+
+#ifdef SIGPWR
+ if (sigpwr_count > MAXSIGQ)
+ WRN("%i SIGPWR in queue. max queue size %i. losing "
+ "siginfo for extra signals.", sigpwr_count, MAXSIGQ);
+ for (n = 0; n < sigpwr_count; n++)
+ {
+ Ecore_Event_Signal_Power *e;
+
+ e = _ecore_event_signal_power_new();
+ if (e)
+ {
+ if ((n < MAXSIGQ) && (sigpwr_info[n].si_signo))
+ e->data = sigpwr_info[n];
+
+ _ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e,
+ _ecore_signal_generic_free, NULL);
+ }
+ sig_count--;
+ }
+ sigpwr_count = 0;
+#endif
+ sig_count = 0;
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+}
+
+static void
+_ecore_signal_callback_set(int sig,
+ Signal_Handler func)
+{
+ struct sigaction sa;
+
+ sa.sa_sigaction = func;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sigaction(sig, &sa, NULL);
+}
+
+static void
+_ecore_signal_callback_ignore(int sig EINA_UNUSED,
+ siginfo_t *si EINA_UNUSED,
+ void *foo EINA_UNUSED)
+{
+}
+
+static void
+_ecore_signal_callback_sigchld(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigchld_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigchld_info[n] = *si;
+ else
+ sigchld_info[n].si_signo = 0;
+ }
+
+ sigchld_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigusr1(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigusr1_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigusr1_info[n] = *si;
+ else
+ sigusr1_info[n].si_signo = 0;
+ }
+ sigusr1_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigusr2(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigusr2_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigusr2_info[n] = *si;
+ else
+ sigusr2_info[n].si_signo = 0;
+ }
+ sigusr2_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sighup(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sighup_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sighup_info[n] = *si;
+ else
+ sighup_info[n].si_signo = 0;
+ }
+ sighup_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigquit(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigquit_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigquit_info[n] = *si;
+ else
+ sigquit_info[n].si_signo = 0;
+ }
+ sigquit_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigint(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigint_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigint_info[n] = *si;
+ else
+ sigint_info[n].si_signo = 0;
+ }
+ sigint_count++;
+ sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigterm(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigterm_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigterm_info[n] = *si;
+ else
+ sigterm_info[n].si_signo = 0;
+ }
+ sigterm_count++;
+ sig_count++;
+}
+
+#ifdef SIGPWR
+static void
+_ecore_signal_callback_sigpwr(int sig EINA_UNUSED,
+ siginfo_t *si,
+ void *foo EINA_UNUSED)
+{
+ volatile sig_atomic_t n;
+ n = sigpwr_count;
+ if (n < MAXSIGQ)
+ {
+ if (si)
+ sigpwr_info[n] = *si;
+ else
+ sigpwr_info[n].si_signo = 0;
+ }
+ sigpwr_count++;
+ sig_count++;
+}
+
+#endif
+
+static Eina_Bool
+_ecore_signal_exe_exit_delay(void *data)
+{
+ Ecore_Exe_Event_Del *e;
+
+ e = data;
+ if (e)
+ {
+ _ecore_exe_doomsday_clock_set(e->exe, NULL);
+ _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
+ _ecore_exe_event_del_free, NULL);
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
diff --git a/src/lib/ecore/ecore_thread.c b/src/lib/ecore/ecore_thread.c
new file mode 100644
index 0000000000..4937ef5290
--- /dev/null
+++ b/src/lib/ecore/ecore_thread.c
@@ -0,0 +1,1509 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#ifdef EFL_HAVE_THREADS
+
+# define LK(x) Eina_Lock x
+# define LKI(x) eina_lock_new(&(x))
+# define LKD(x) eina_lock_free(&(x))
+# define LKL(x) eina_lock_take(&(x))
+# define LKU(x) eina_lock_release(&(x))
+
+# define CD(x) Eina_Condition x
+# define CDI(x, m) eina_condition_new(&(x), &(m))
+# define CDD(x) eina_condition_free(&(x))
+# define CDB(x) eina_condition_broadcast(&(x))
+# define CDW(x, t) eina_condition_timedwait(&(x), t)
+
+# define LRWK(x) Eina_RWLock x
+# define LRWKI(x) eina_rwlock_new(&(x));
+# define LRWKD(x) eina_rwlock_free(&(x));
+# define LRWKWL(x) eina_rwlock_take_write(&(x));
+# define LRWKRL(x) eina_rwlock_take_read(&(x));
+# define LRWKU(x) eina_rwlock_release(&(x));
+
+# define PH(x) Eina_Thread x
+# define PHE(x, y) eina_thread_equal(x, y)
+# define PHS() eina_thread_self()
+# define PHC(x, f, d) eina_thread_create(&(x), EINA_THREAD_BACKGROUND, -1, (void *)f, d)
+# define PHJ(x) eina_thread_join(x)
+
+# ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+# ifdef __linux__
+# include <sched.h>
+# include <sys/resource.h>
+# include <unistd.h>
+# include <sys/syscall.h>
+# include <errno.h>
+# endif
+
+# else /* EFL_HAVE_WIN32_THREADS */
+
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+
+# endif
+
+#endif
+
+typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker;
+typedef struct _Ecore_Pthread Ecore_Pthread;
+typedef struct _Ecore_Thread_Data Ecore_Thread_Data;
+
+struct _Ecore_Thread_Data
+{
+ void *data;
+ Eina_Free_Cb cb;
+};
+
+struct _Ecore_Pthread_Worker
+{
+ union {
+ struct
+ {
+ Ecore_Thread_Cb func_blocking;
+ } short_run;
+ struct
+ {
+ Ecore_Thread_Cb func_heavy;
+ Ecore_Thread_Notify_Cb func_notify;
+
+ Ecore_Pthread_Worker *direct_worker;
+
+ int send;
+ int received;
+ } feedback_run;
+ struct {
+ Ecore_Thread_Cb func_main;
+ Ecore_Thread_Notify_Cb func_notify;
+
+ Ecore_Pipe *send;
+ Ecore_Pthread_Worker *direct_worker;
+
+ struct {
+ int send;
+ int received;
+ } from, to;
+ } message_run;
+ } u;
+
+ Ecore_Thread_Cb func_cancel;
+ Ecore_Thread_Cb func_end;
+#ifdef EFL_HAVE_THREADS
+ PH(self);
+ Eina_Hash *hash;
+ CD(cond);
+ LK(mutex);
+#endif
+
+ const void *data;
+
+ int cancel;
+
+#ifdef EFL_HAVE_THREADS
+ LK(cancel_mutex);
+#endif
+
+ Eina_Bool message_run : 1;
+ Eina_Bool feedback_run : 1;
+ Eina_Bool kill : 1;
+ Eina_Bool reschedule : 1;
+ Eina_Bool no_queue : 1;
+};
+
+#ifdef EFL_HAVE_THREADS
+typedef struct _Ecore_Pthread_Notify Ecore_Pthread_Notify;
+struct _Ecore_Pthread_Notify
+{
+ Ecore_Pthread_Worker *work;
+ const void *user_data;
+};
+
+typedef void *(*Ecore_Thread_Sync_Cb)(void* data, Ecore_Thread *thread);
+
+typedef struct _Ecore_Pthread_Message Ecore_Pthread_Message;
+struct _Ecore_Pthread_Message
+{
+ union {
+ Ecore_Thread_Cb async;
+ Ecore_Thread_Sync_Cb sync;
+ } u;
+
+ const void *data;
+
+ int code;
+
+ Eina_Bool callback : 1;
+ Eina_Bool sync : 1;
+};
+
+#endif
+
+static int _ecore_thread_count_max = 0;
+
+#ifdef EFL_HAVE_THREADS
+
+static void _ecore_thread_handler(void *data);
+
+static int _ecore_thread_count = 0;
+
+static Eina_List *_ecore_running_job = NULL;
+static Eina_List *_ecore_pending_job_threads = NULL;
+static Eina_List *_ecore_pending_job_threads_feedback = NULL;
+static LK(_ecore_pending_job_threads_mutex);
+static LK(_ecore_running_job_mutex);
+
+static Eina_Hash *_ecore_thread_global_hash = NULL;
+static LRWK(_ecore_thread_global_hash_lock);
+static LK(_ecore_thread_global_hash_mutex);
+static CD(_ecore_thread_global_hash_cond);
+
+static Eina_Bool have_main_loop_thread = 0;
+
+static Eina_Trash *_ecore_thread_worker_trash = NULL;
+static int _ecore_thread_worker_count = 0;
+
+static void *_ecore_thread_worker(void *);
+static Ecore_Pthread_Worker *_ecore_thread_worker_new(void);
+
+static PH(get_main_loop_thread) (void)
+{
+ static PH(main_loop_thread);
+ static pid_t main_loop_pid;
+ pid_t pid = getpid();
+
+ if (pid != main_loop_pid)
+ {
+ main_loop_pid = pid;
+ main_loop_thread = PHS();
+ have_main_loop_thread = 1;
+ }
+
+ return main_loop_thread;
+}
+
+static void
+_ecore_thread_worker_free(Ecore_Pthread_Worker *worker)
+{
+ LKD(worker->cancel_mutex);
+ CDD(worker->cond);
+ LKD(worker->mutex);
+
+ if (_ecore_thread_worker_count > ((_ecore_thread_count_max + 1) * 16))
+ {
+ _ecore_thread_worker_count--;
+ free(worker);
+ return;
+ }
+
+ eina_trash_push(&_ecore_thread_worker_trash, worker);
+}
+
+static void
+_ecore_thread_data_free(void *data)
+{
+ Ecore_Thread_Data *d = data;
+
+ if (d->cb) d->cb(d->data);
+ free(d);
+}
+
+static void
+_ecore_thread_join(PH(thread))
+{
+ PHJ(thread);
+}
+
+static void
+_ecore_thread_kill(Ecore_Pthread_Worker *work)
+{
+ if (work->cancel)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void *)work->data, (Ecore_Thread *)work);
+ }
+ else
+ {
+ if (work->func_end)
+ work->func_end((void *)work->data, (Ecore_Thread *)work);
+ }
+
+ if (work->feedback_run)
+ {
+ if (work->u.feedback_run.direct_worker)
+ _ecore_thread_worker_free(work->u.feedback_run.direct_worker);
+ }
+ if (work->hash)
+ eina_hash_free(work->hash);
+ _ecore_thread_worker_free(work);
+}
+
+static void
+_ecore_thread_handler(void *data)
+{
+ Ecore_Pthread_Worker *work = data;
+
+ if (work->feedback_run)
+ {
+ if (work->u.feedback_run.send != work->u.feedback_run.received)
+ {
+ work->kill = EINA_TRUE;
+ return;
+ }
+ }
+
+ _ecore_thread_kill(work);
+}
+
+#if 0
+static void
+_ecore_nothing_handler(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED)
+{
+}
+#endif
+
+static void
+_ecore_notify_handler(void *data)
+{
+ Ecore_Pthread_Notify *notify = data;
+ Ecore_Pthread_Worker *work = notify->work;
+ void *user_data = (void*) notify->user_data;
+
+ work->u.feedback_run.received++;
+
+ if (work->u.feedback_run.func_notify)
+ work->u.feedback_run.func_notify((void *)work->data, (Ecore_Thread *)work, user_data);
+
+ /* Force reading all notify event before killing the thread */
+ if (work->kill && work->u.feedback_run.send == work->u.feedback_run.received)
+ {
+ _ecore_thread_kill(work);
+ }
+
+ free(notify);
+}
+
+static void
+_ecore_message_notify_handler(void *data)
+{
+ Ecore_Pthread_Notify *notify = data;
+ Ecore_Pthread_Worker *work = notify->work;
+ Ecore_Pthread_Message *user_data = (void *) notify->user_data;
+ Eina_Bool delete = EINA_TRUE;
+
+ work->u.message_run.from.received++;
+
+ if (!user_data->callback)
+ {
+ if (work->u.message_run.func_notify)
+ work->u.message_run.func_notify((void *) work->data, (Ecore_Thread *) work, (void *) user_data->data);
+ }
+ else
+ {
+ if (user_data->sync)
+ {
+ user_data->data = user_data->u.sync((void*) user_data->data, (Ecore_Thread *) work);
+ user_data->callback = EINA_FALSE;
+ user_data->code = INT_MAX;
+ ecore_pipe_write(work->u.message_run.send, &user_data, sizeof (Ecore_Pthread_Message *));
+
+ delete = EINA_FALSE;
+ }
+ else
+ {
+ user_data->u.async((void*) user_data->data, (Ecore_Thread *) work);
+ }
+ }
+
+ if (delete)
+ {
+ free(user_data);
+ }
+
+ /* Force reading all notify event before killing the thread */
+ if (work->kill && work->u.message_run.from.send == work->u.message_run.from.received)
+ {
+ _ecore_thread_kill(work);
+ }
+ free(notify);
+}
+
+static void
+_ecore_short_job(PH(thread))
+{
+ Ecore_Pthread_Worker *work;
+ int cancel;
+
+ LKL(_ecore_pending_job_threads_mutex);
+
+ if (!_ecore_pending_job_threads)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ return;
+ }
+
+ work = eina_list_data_get(_ecore_pending_job_threads);
+ _ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads,
+ _ecore_pending_job_threads);
+ LKU(_ecore_pending_job_threads_mutex);
+
+ LKL(_ecore_running_job_mutex);
+ _ecore_running_job = eina_list_append(_ecore_running_job, work);
+ LKU(_ecore_running_job_mutex);
+
+ LKL(work->cancel_mutex);
+ cancel = work->cancel;
+ LKU(work->cancel_mutex);
+ work->self = thread;
+ if (!cancel)
+ work->u.short_run.func_blocking((void *) work->data, (Ecore_Thread*) work);
+
+ LKL(_ecore_running_job_mutex);
+ _ecore_running_job = eina_list_remove(_ecore_running_job, work);
+ LKU(_ecore_running_job_mutex);
+
+ if (work->reschedule)
+ {
+ work->reschedule = EINA_FALSE;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
+ LKU(_ecore_pending_job_threads_mutex);
+ }
+ else
+ {
+ ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
+ }
+}
+
+static void
+_ecore_feedback_job(PH(thread))
+{
+ Ecore_Pthread_Worker *work;
+ int cancel;
+
+ LKL(_ecore_pending_job_threads_mutex);
+
+ if (!_ecore_pending_job_threads_feedback)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ return;
+ }
+
+ work = eina_list_data_get(_ecore_pending_job_threads_feedback);
+ _ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback,
+ _ecore_pending_job_threads_feedback);
+ LKU(_ecore_pending_job_threads_mutex);
+ LKL(_ecore_running_job_mutex);
+ _ecore_running_job = eina_list_append(_ecore_running_job, work);
+ LKU(_ecore_running_job_mutex);
+
+ LKL(work->cancel_mutex);
+ cancel = work->cancel;
+ LKU(work->cancel_mutex);
+ work->self = thread;
+ if (!cancel)
+ work->u.feedback_run.func_heavy((void *) work->data, (Ecore_Thread *) work);
+
+ LKL(_ecore_running_job_mutex);
+ _ecore_running_job = eina_list_remove(_ecore_running_job, work);
+ LKU(_ecore_running_job_mutex);
+
+ if (work->reschedule)
+ {
+ work->reschedule = EINA_FALSE;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, work);
+ LKU(_ecore_pending_job_threads_mutex);
+ }
+ else
+ {
+ ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
+ }
+}
+
+static void *
+_ecore_direct_worker(Ecore_Pthread_Worker *work)
+{
+ work->self = PHS();
+ if (work->message_run)
+ work->u.message_run.func_main((void *) work->data, (Ecore_Thread *) work);
+ else
+ work->u.feedback_run.func_heavy((void *) work->data, (Ecore_Thread *) work);
+
+ ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work);
+
+ ecore_main_loop_thread_safe_call_async((Ecore_Cb) _ecore_thread_join,
+ (void*) PHS());
+
+ return NULL;
+}
+
+static void *
+_ecore_thread_worker(void *data EINA_UNUSED)
+{
+restart:
+ _ecore_short_job(PHS());
+ _ecore_feedback_job(PHS());
+
+ /* FIXME: Check if there is feedback running task todo, and switch to feedback run handler. */
+
+ LKL(_ecore_pending_job_threads_mutex);
+ if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ goto restart;
+ }
+ LKU(_ecore_pending_job_threads_mutex);
+
+ /* Sleep a little to prevent premature death */
+#ifdef _WIN32
+ Sleep(1); /* around 50ms */
+#else
+ usleep(50);
+#endif
+
+ LKL(_ecore_pending_job_threads_mutex);
+ if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ goto restart;
+ }
+ _ecore_thread_count--;
+
+ ecore_main_loop_thread_safe_call_async((Ecore_Cb) _ecore_thread_join,
+ (void*) PHS());
+ LKU(_ecore_pending_job_threads_mutex);
+
+ return NULL;
+}
+
+#endif
+
+static Ecore_Pthread_Worker *
+_ecore_thread_worker_new(void)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *result;
+
+ result = eina_trash_pop(&_ecore_thread_worker_trash);
+
+ if (!result)
+ {
+ result = calloc(1, sizeof(Ecore_Pthread_Worker));
+ _ecore_thread_worker_count++;
+ }
+
+ LKI(result->cancel_mutex);
+ LKI(result->mutex);
+ CDI(result->cond, result->mutex);
+
+ return result;
+#else
+ return malloc(sizeof (Ecore_Pthread_Worker));
+#endif
+}
+
+void
+_ecore_thread_init(void)
+{
+ _ecore_thread_count_max = eina_cpu_count();
+ if (_ecore_thread_count_max <= 0)
+ _ecore_thread_count_max = 1;
+
+#ifdef EFL_HAVE_THREADS
+ LKI(_ecore_pending_job_threads_mutex);
+ LRWKI(_ecore_thread_global_hash_lock);
+ LKI(_ecore_thread_global_hash_mutex);
+ LKI(_ecore_running_job_mutex);
+ CDI(_ecore_thread_global_hash_cond, _ecore_thread_global_hash_mutex);
+#endif
+}
+
+void
+_ecore_thread_shutdown(void)
+{
+ /* FIXME: If function are still running in the background, should we kill them ? */
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *work;
+ Eina_List *l;
+ Eina_Bool test;
+ int iteration = 0;
+
+ LKL(_ecore_pending_job_threads_mutex);
+
+ EINA_LIST_FREE(_ecore_pending_job_threads, work)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void *)work->data, (Ecore_Thread *) work);
+ free(work);
+ }
+
+ EINA_LIST_FREE(_ecore_pending_job_threads_feedback, work)
+ {
+ if (work->func_cancel)
+ work->func_cancel((void *)work->data, (Ecore_Thread *) work);
+ free(work);
+ }
+
+ LKU(_ecore_pending_job_threads_mutex);
+ LKL(_ecore_running_job_mutex);
+
+ EINA_LIST_FOREACH(_ecore_running_job, l, work)
+ ecore_thread_cancel((Ecore_Thread*) work);
+
+ LKU(_ecore_running_job_mutex);
+
+ do
+ {
+ LKL(_ecore_pending_job_threads_mutex);
+ if (_ecore_thread_count > 0)
+ {
+ test = EINA_TRUE;
+ }
+ else
+ {
+ test = EINA_FALSE;
+ }
+ LKU(_ecore_pending_job_threads_mutex);
+ iteration++;
+ if (test) usleep(50000);
+ }
+ while (test == EINA_TRUE && iteration < 20);
+
+ if (iteration == 20 && _ecore_thread_count > 0)
+ {
+ ERR("%i of the child thread are still running after 1s. This can lead to a segv. Sorry.", _ecore_thread_count);
+ }
+
+ if (_ecore_thread_global_hash)
+ eina_hash_free(_ecore_thread_global_hash);
+ have_main_loop_thread = 0;
+
+ while ((work = eina_trash_pop(&_ecore_thread_worker_trash)))
+ {
+ free(work);
+ }
+
+ LKD(_ecore_pending_job_threads_mutex);
+ LRWKD(_ecore_thread_global_hash_lock);
+ LKD(_ecore_thread_global_hash_mutex);
+ LKD(_ecore_running_job_mutex);
+ CDD(_ecore_thread_global_hash_cond);
+#endif
+}
+
+EAPI Ecore_Thread *
+ecore_thread_run(Ecore_Thread_Cb func_blocking,
+ Ecore_Thread_Cb func_end,
+ Ecore_Thread_Cb func_cancel,
+ const void *data)
+{
+ Ecore_Pthread_Worker *work;
+ Eina_Bool tried = EINA_FALSE;
+#ifdef EFL_HAVE_THREADS
+ PH(thread);
+#endif
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+
+ if (!func_blocking) return NULL;
+
+ work = _ecore_thread_worker_new();
+ if (!work)
+ {
+ if (func_cancel)
+ func_cancel((void *)data, NULL);
+ return NULL;
+ }
+
+ work->u.short_run.func_blocking = func_blocking;
+ work->func_end = func_end;
+ work->func_cancel = func_cancel;
+ work->cancel = EINA_FALSE;
+ work->feedback_run = EINA_FALSE;
+ work->message_run = EINA_FALSE;
+ work->kill = EINA_FALSE;
+ work->reschedule = EINA_FALSE;
+ work->no_queue = EINA_FALSE;
+ work->data = data;
+
+#ifdef EFL_HAVE_THREADS
+ work->self = 0;
+ work->hash = NULL;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work);
+
+ if (_ecore_thread_count == _ecore_thread_count_max)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ return (Ecore_Thread *)work;
+ }
+
+ LKU(_ecore_pending_job_threads_mutex);
+
+ /* One more thread could be created. */
+ eina_threads_init();
+
+ LKL(_ecore_pending_job_threads_mutex);
+
+ retry:
+ if (PHC(thread, _ecore_thread_worker, NULL))
+ {
+ _ecore_thread_count++;
+ LKU(_ecore_pending_job_threads_mutex);
+ return (Ecore_Thread *)work;
+ }
+ if (!tried)
+ {
+ _ecore_main_call_flush();
+ tried = EINA_TRUE;
+ goto retry;
+ }
+
+ if (_ecore_thread_count == 0)
+ {
+ _ecore_pending_job_threads = eina_list_remove(_ecore_pending_job_threads, work);
+
+ if (work->func_cancel)
+ work->func_cancel((void *) work->data, (Ecore_Thread *) work);
+
+ _ecore_thread_worker_free(work);
+ work = NULL;
+ }
+ LKU(_ecore_pending_job_threads_mutex);
+
+ eina_threads_shutdown();
+
+ return (Ecore_Thread *)work;
+#else
+ /*
+ If no thread and as we don't want to break app that rely on this
+ facility, we will lock the interface until we are done.
+ */
+ do {
+ /* Handle reschedule by forcing it here. That would mean locking the app,
+ * would be better with an idler, but really to complex for a case where
+ * thread should really exist.
+ */
+ work->reschedule = EINA_FALSE;
+
+ func_blocking((void *)data, (Ecore_Thread *)work);
+ if (work->cancel == EINA_FALSE) func_end((void *)data, (Ecore_Thread *)work);
+ else func_cancel((void *)data, (Ecore_Thread *)work);
+ } while (work->reschedule == EINA_TRUE);
+
+ free(work);
+
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_cancel(Ecore_Thread *thread)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *volatile work = (Ecore_Pthread_Worker *)thread;
+ Eina_List *l;
+ int cancel;
+
+ if (!work)
+ return EINA_TRUE;
+ LKL(work->cancel_mutex);
+ cancel = work->cancel;
+ LKU(work->cancel_mutex);
+ if (cancel)
+ return EINA_FALSE;
+
+ if (work->feedback_run)
+ {
+ if (work->kill)
+ return EINA_TRUE;
+ if (work->u.feedback_run.send != work->u.feedback_run.received)
+ goto on_exit;
+ }
+
+ LKL(_ecore_pending_job_threads_mutex);
+
+ if ((have_main_loop_thread) &&
+ (PHE(get_main_loop_thread(), PHS())))
+ {
+ if (!work->feedback_run)
+ EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work)
+ {
+ if ((void *)work == (void *)thread)
+ {
+ _ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, l);
+
+ LKU(_ecore_pending_job_threads_mutex);
+
+ if (work->func_cancel)
+ work->func_cancel((void *)work->data, (Ecore_Thread *)work);
+ free(work);
+
+ return EINA_TRUE;
+ }
+ }
+ else
+ EINA_LIST_FOREACH(_ecore_pending_job_threads_feedback, l, work)
+ {
+ if ((void *)work == (void *)thread)
+ {
+ _ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback, l);
+
+ LKU(_ecore_pending_job_threads_mutex);
+
+ if (work->func_cancel)
+ work->func_cancel((void *)work->data, (Ecore_Thread *)work);
+ free(work);
+
+ return EINA_TRUE;
+ }
+ }
+ }
+
+ LKU(_ecore_pending_job_threads_mutex);
+
+ work = (Ecore_Pthread_Worker *)thread;
+
+ /* Delay the destruction */
+ on_exit:
+ LKL(work->cancel_mutex);
+ work->cancel = EINA_TRUE;
+ LKU(work->cancel_mutex);
+
+ return EINA_FALSE;
+#else
+ (void) thread;
+ return EINA_TRUE;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_check(Ecore_Thread *thread)
+{
+ Ecore_Pthread_Worker *volatile worker = (Ecore_Pthread_Worker *) thread;
+ int cancel;
+
+ if (!worker) return EINA_TRUE;
+#ifdef EFL_HAVE_THREADS
+ LKL(worker->cancel_mutex);
+#endif
+ cancel = worker->cancel;
+ /* FIXME: there is an insane bug driving me nuts here. I don't know if
+ it's a race condition, some cache issue or some alien attack on our software.
+ But ecore_thread_check will only work correctly with a printf, all the volatile,
+ lock and even usleep don't help here... */
+ /* fprintf(stderr, "wc: %i\n", cancel); */
+#ifdef EFL_HAVE_THREADS
+ LKU(worker->cancel_mutex);
+#endif
+ return cancel;
+}
+
+EAPI Ecore_Thread *
+ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy,
+ Ecore_Thread_Notify_Cb func_notify,
+ Ecore_Thread_Cb func_end,
+ Ecore_Thread_Cb func_cancel,
+ const void *data,
+ Eina_Bool try_no_queue)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker;
+ Eina_Bool tried = EINA_FALSE;
+ PH(thread);
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+
+ if (!func_heavy) return NULL;
+
+ worker = _ecore_thread_worker_new();
+ if (!worker) goto on_error;
+
+ worker->u.feedback_run.func_heavy = func_heavy;
+ worker->u.feedback_run.func_notify = func_notify;
+ worker->hash = NULL;
+ worker->func_cancel = func_cancel;
+ worker->func_end = func_end;
+ worker->data = data;
+ worker->cancel = EINA_FALSE;
+ worker->message_run = EINA_FALSE;
+ worker->feedback_run = EINA_TRUE;
+ worker->kill = EINA_FALSE;
+ worker->reschedule = EINA_FALSE;
+ worker->self = 0;
+
+ worker->u.feedback_run.send = 0;
+ worker->u.feedback_run.received = 0;
+
+ worker->u.feedback_run.direct_worker = NULL;
+
+ if (try_no_queue)
+ {
+ PH(t);
+
+ worker->u.feedback_run.direct_worker = _ecore_thread_worker_new();
+ worker->no_queue = EINA_TRUE;
+
+ eina_threads_init();
+
+ retry_direct:
+ if (PHC(t, _ecore_direct_worker, worker))
+ return (Ecore_Thread *)worker;
+ if (!tried)
+ {
+ _ecore_main_call_flush();
+ tried = EINA_TRUE;
+ goto retry_direct;
+ }
+
+ if (worker->u.feedback_run.direct_worker)
+ {
+ _ecore_thread_worker_free(worker->u.feedback_run.direct_worker);
+ worker->u.feedback_run.direct_worker = NULL;
+ }
+
+ eina_threads_shutdown();
+ }
+
+ worker->no_queue = EINA_FALSE;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ _ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, worker);
+
+ if (_ecore_thread_count == _ecore_thread_count_max)
+ {
+ LKU(_ecore_pending_job_threads_mutex);
+ return (Ecore_Thread *)worker;
+ }
+
+ LKU(_ecore_pending_job_threads_mutex);
+
+ /* One more thread could be created. */
+ eina_threads_init();
+
+ LKL(_ecore_pending_job_threads_mutex);
+ retry:
+ if (PHC(thread, _ecore_thread_worker, NULL))
+ {
+ _ecore_thread_count++;
+ LKU(_ecore_pending_job_threads_mutex);
+ return (Ecore_Thread *)worker;
+ }
+ if (!tried)
+ {
+ _ecore_main_call_flush();
+ tried = EINA_TRUE;
+ goto retry;
+ }
+ LKU(_ecore_pending_job_threads_mutex);
+
+ eina_threads_shutdown();
+
+on_error:
+ LKL(_ecore_pending_job_threads_mutex);
+ if (_ecore_thread_count == 0)
+ {
+ _ecore_pending_job_threads_feedback = eina_list_remove(_ecore_pending_job_threads_feedback,
+ worker);
+
+ if (func_cancel) func_cancel((void *)data, NULL);
+
+ if (worker)
+ {
+ CDD(worker->cond);
+ LKD(worker->mutex);
+ free(worker);
+ worker = NULL;
+ }
+ }
+ LKU(_ecore_pending_job_threads_mutex);
+
+ return (Ecore_Thread *)worker;
+#else
+ Ecore_Pthread_Worker worker;
+
+ (void)try_no_queue;
+
+ /*
+ If no thread and as we don't want to break app that rely on this
+ facility, we will lock the interface until we are done.
+ */
+ worker.u.feedback_run.func_heavy = func_heavy;
+ worker.u.feedback_run.func_notify = func_notify;
+ worker.u.feedback_run.send = 0;
+ worker.u.feedback_run.received = 0;
+ worker.func_cancel = func_cancel;
+ worker.func_end = func_end;
+ worker.data = data;
+ worker.cancel = EINA_FALSE;
+ worker.feedback_run = EINA_TRUE;
+ worker.message_run = EINA_FALSE;
+ worker.kill = EINA_FALSE;
+
+ do {
+ worker.reschedule = EINA_FALSE;
+
+ func_heavy((void *)data, (Ecore_Thread *)&worker);
+
+ if (worker.cancel) func_cancel((void *)data, (Ecore_Thread *)&worker);
+ else func_end((void *)data, (Ecore_Thread *)&worker);
+ } while (worker.reschedule == EINA_TRUE);
+
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_feedback(Ecore_Thread *thread,
+ const void *data)
+{
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+
+ if (!worker) return EINA_FALSE;
+
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return EINA_FALSE;
+
+ if (worker->feedback_run)
+ {
+ Ecore_Pthread_Notify *notify;
+
+ notify = malloc(sizeof (Ecore_Pthread_Notify));
+ if (!notify) return EINA_FALSE;
+
+ notify->user_data = data;
+ notify->work = worker;
+ worker->u.feedback_run.send++;
+
+ ecore_main_loop_thread_safe_call_async(_ecore_notify_handler, notify);
+ }
+ else if (worker->message_run)
+ {
+ Ecore_Pthread_Message *msg;
+ Ecore_Pthread_Notify *notify;
+
+ msg = malloc(sizeof (Ecore_Pthread_Message));
+ if (!msg) return EINA_FALSE;
+ msg->data = data;
+ msg->callback = EINA_FALSE;
+ msg->sync = EINA_FALSE;
+
+ notify = malloc(sizeof (Ecore_Pthread_Notify));
+ if (!notify)
+ {
+ free(msg);
+ return EINA_FALSE;
+ }
+ notify->work = worker;
+ notify->user_data = msg;
+
+ worker->u.message_run.from.send++;
+ ecore_main_loop_thread_safe_call_async(_ecore_message_notify_handler, notify);
+ }
+ else
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+#else
+ worker->u.feedback_run.func_notify((void *)worker->data, thread, (void *)data);
+
+ return EINA_TRUE;
+#endif
+}
+
+#if 0
+EAPI Ecore_Thread *
+ecore_thread_message_run(Ecore_Thread_Cb func_main,
+ Ecore_Thread_Notify_Cb func_notify,
+ Ecore_Thread_Cb func_end,
+ Ecore_Thread_Cb func_cancel,
+ const void *data)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker;
+ PH(t);
+
+ if (!func_main) return NULL;
+
+ worker = _ecore_thread_worker_new();
+ if (!worker) return NULL;
+
+ worker->u.message_run.func_main = func_main;
+ worker->u.message_run.func_notify = func_notify;
+ worker->u.message_run.direct_worker = _ecore_thread_worker_new();
+ worker->u.message_run.send = ecore_pipe_add(_ecore_nothing_handler, worker);
+ worker->u.message_run.from.send = 0;
+ worker->u.message_run.from.received = 0;
+ worker->u.message_run.to.send = 0;
+ worker->u.message_run.to.received = 0;
+
+ ecore_pipe_freeze(worker->u.message_run.send);
+
+ worker->func_cancel = func_cancel;
+ worker->func_end = func_end;
+ worker->hash = NULL;
+ worker->data = data;
+
+ worker->cancel = EINA_FALSE;
+ worker->message_run = EINA_TRUE;
+ worker->feedback_run = EINA_FALSE;
+ worker->kill = EINA_FALSE;
+ worker->reschedule = EINA_FALSE;
+ worker->no_queue = EINA_FALSE;
+ worker->self = 0;
+
+ eina_threads_init();
+
+ if (PHC(t, _ecore_direct_worker, worker))
+ return (Ecore_Thread*) worker;
+
+ eina_threads_shutdown();
+
+ if (worker->u.message_run.direct_worker) _ecore_thread_worker_free(worker->u.message_run.direct_worker);
+ if (worker->u.message_run.send) ecore_pipe_del(worker->u.message_run.send);
+
+ CDD(worker->cond);
+ LKD(worker->mutex);
+#else
+ /* Note: This type of thread can't and never will work without thread support */
+ WRN("ecore_thread_message_run called, but threads disable in Ecore, things will go wrong. Starting now !");
+# warning "You disabled threads support in ecore, I hope you know what you are doing !"
+#endif
+
+ func_cancel((void *) data, NULL);
+
+ return NULL;
+}
+#endif
+
+EAPI Eina_Bool
+ecore_thread_reschedule(Ecore_Thread *thread)
+{
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+
+ if (!worker) return EINA_FALSE;
+
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return EINA_FALSE;
+#endif
+
+ worker->reschedule = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+EAPI int
+ecore_thread_active_get(void)
+{
+#ifdef EFL_HAVE_THREADS
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ return _ecore_thread_count;
+#else
+ return 0;
+#endif
+}
+
+EAPI int
+ecore_thread_pending_get(void)
+{
+#ifdef EFL_HAVE_THREADS
+ int ret;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ LKL(_ecore_pending_job_threads_mutex);
+ ret = eina_list_count(_ecore_pending_job_threads);
+ LKU(_ecore_pending_job_threads_mutex);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+EAPI int
+ecore_thread_pending_feedback_get(void)
+{
+#ifdef EFL_HAVE_THREADS
+ int ret;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ LKL(_ecore_pending_job_threads_mutex);
+ ret = eina_list_count(_ecore_pending_job_threads_feedback);
+ LKU(_ecore_pending_job_threads_mutex);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+EAPI int
+ecore_thread_pending_total_get(void)
+{
+#ifdef EFL_HAVE_THREADS
+ int ret;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ LKL(_ecore_pending_job_threads_mutex);
+ ret = eina_list_count(_ecore_pending_job_threads) + eina_list_count(_ecore_pending_job_threads_feedback);
+ LKU(_ecore_pending_job_threads_mutex);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+EAPI int
+ecore_thread_max_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
+ return _ecore_thread_count_max;
+}
+
+EAPI void
+ecore_thread_max_set(int num)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ if (num < 1) return;
+ /* avoid doing something hilarious by blocking dumb users */
+ if (num > (16 * eina_cpu_count())) num = 16 * eina_cpu_count();
+
+ _ecore_thread_count_max = num;
+}
+
+EAPI void
+ecore_thread_max_reset(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_thread_count_max = eina_cpu_count();
+}
+
+EAPI int
+ecore_thread_available_get(void)
+{
+#ifdef EFL_HAVE_THREADS
+ int ret;
+
+ LKL(_ecore_pending_job_threads_mutex);
+ ret = _ecore_thread_count_max - _ecore_thread_count;
+ LKU(_ecore_pending_job_threads_mutex);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_local_data_add(Ecore_Thread *thread,
+ const char *key,
+ void *value,
+ Eina_Free_Cb cb,
+ Eina_Bool direct)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+ Ecore_Thread_Data *d;
+ Eina_Bool ret;
+#endif
+
+ if ((!thread) || (!key) || (!value))
+ return EINA_FALSE;
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return EINA_FALSE;
+
+ if (!worker->hash)
+ worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
+
+ if (!worker->hash)
+ return EINA_FALSE;
+
+ if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+ return EINA_FALSE;
+
+ d->data = value;
+ d->cb = cb;
+
+ if (direct)
+ ret = eina_hash_direct_add(worker->hash, key, d);
+ else
+ ret = eina_hash_add(worker->hash, key, d);
+ CDB(worker->cond);
+ return ret;
+#else
+ (void) cb;
+ (void) direct;
+ return EINA_FALSE;
+#endif
+}
+
+EAPI void *
+ecore_thread_local_data_set(Ecore_Thread *thread,
+ const char *key,
+ void *value,
+ Eina_Free_Cb cb)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+ Ecore_Thread_Data *d, *r;
+ void *ret;
+#endif
+
+ if ((!thread) || (!key) || (!value))
+ return NULL;
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return NULL;
+
+ if (!worker->hash)
+ worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
+
+ if (!worker->hash)
+ return NULL;
+
+ if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+ return NULL;
+
+ d->data = value;
+ d->cb = cb;
+
+ r = eina_hash_set(worker->hash, key, d);
+ CDB(worker->cond);
+ ret = r->data;
+ free(r);
+ return ret;
+#else
+ (void) cb;
+ return NULL;
+#endif
+}
+
+EAPI void *
+ecore_thread_local_data_find(Ecore_Thread *thread,
+ const char *key)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+ Ecore_Thread_Data *d;
+#endif
+
+ if ((!thread) || (!key))
+ return NULL;
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return NULL;
+
+ if (!worker->hash)
+ return NULL;
+
+ d = eina_hash_find(worker->hash, key);
+ if (d)
+ return d->data;
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_local_data_del(Ecore_Thread *thread,
+ const char *key)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread;
+#endif
+
+ if ((!thread) || (!key))
+ return EINA_FALSE;
+#ifdef EFL_HAVE_THREADS
+ if (!PHE(worker->self, PHS())) return EINA_FALSE;
+
+ if (!worker->hash)
+ return EINA_FALSE;
+ return eina_hash_del_by_key(worker->hash, key);
+#else
+ return EINA_TRUE;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_global_data_add(const char *key,
+ void *value,
+ Eina_Free_Cb cb,
+ Eina_Bool direct)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Thread_Data *d;
+ Eina_Bool ret;
+#endif
+
+ if ((!key) || (!value))
+ return EINA_FALSE;
+#ifdef EFL_HAVE_THREADS
+ LRWKWL(_ecore_thread_global_hash_lock);
+ if (!_ecore_thread_global_hash)
+ _ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free);
+ LRWKU(_ecore_thread_global_hash_lock);
+
+ if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+ return EINA_FALSE;
+
+ d->data = value;
+ d->cb = cb;
+
+ if (!_ecore_thread_global_hash)
+ return EINA_FALSE;
+ LRWKWL(_ecore_thread_global_hash_lock);
+ if (direct)
+ ret = eina_hash_direct_add(_ecore_thread_global_hash, key, d);
+ else
+ ret = eina_hash_add(_ecore_thread_global_hash, key, d);
+ LRWKU(_ecore_thread_global_hash_lock);
+ CDB(_ecore_thread_global_hash_cond);
+ return ret;
+#else
+ (void) cb;
+ (void) direct;
+ return EINA_TRUE;
+#endif
+}
+
+EAPI void *
+ecore_thread_global_data_set(const char *key,
+ void *value,
+ Eina_Free_Cb cb)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Thread_Data *d, *r;
+ void *ret;
+#endif
+
+ if ((!key) || (!value))
+ return NULL;
+#ifdef EFL_HAVE_THREADS
+ LRWKWL(_ecore_thread_global_hash_lock);
+ if (!_ecore_thread_global_hash)
+ _ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free);
+ LRWKU(_ecore_thread_global_hash_lock);
+
+ if (!_ecore_thread_global_hash)
+ return NULL;
+
+ if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+ return NULL;
+
+ d->data = value;
+ d->cb = cb;
+
+ LRWKWL(_ecore_thread_global_hash_lock);
+ r = eina_hash_set(_ecore_thread_global_hash, key, d);
+ LRWKU(_ecore_thread_global_hash_lock);
+ CDB(_ecore_thread_global_hash_cond);
+
+ ret = r->data;
+ free(r);
+ return ret;
+#else
+ (void) cb;
+ return NULL;
+#endif
+}
+
+EAPI void *
+ecore_thread_global_data_find(const char *key)
+{
+#ifdef EFL_HAVE_THREADS
+ Ecore_Thread_Data *ret;
+#endif
+
+ if (!key)
+ return NULL;
+#ifdef EFL_HAVE_THREADS
+ if (!_ecore_thread_global_hash) return NULL;
+
+ LRWKRL(_ecore_thread_global_hash_lock);
+ ret = eina_hash_find(_ecore_thread_global_hash, key);
+ LRWKU(_ecore_thread_global_hash_lock);
+ if (ret)
+ return ret->data;
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_thread_global_data_del(const char *key)
+{
+#ifdef EFL_HAVE_THREADS
+ Eina_Bool ret;
+#endif
+
+ if (!key)
+ return EINA_FALSE;
+#ifdef EFL_HAVE_THREADS
+ if (!_ecore_thread_global_hash)
+ return EINA_FALSE;
+
+ LRWKWL(_ecore_thread_global_hash_lock);
+ ret = eina_hash_del_by_key(_ecore_thread_global_hash, key);
+ LRWKU(_ecore_thread_global_hash_lock);
+ return ret;
+#else
+ return EINA_TRUE;
+#endif
+}
+
+EAPI void *
+ecore_thread_global_data_wait(const char *key,
+ double seconds)
+{
+#ifdef EFL_HAVE_THREADS
+ double tm = 0;
+ Ecore_Thread_Data *ret = NULL;
+#endif
+
+ if (!key)
+ return NULL;
+#ifdef EFL_HAVE_THREADS
+ if (!_ecore_thread_global_hash)
+ return NULL;
+ if (seconds > 0)
+ tm = ecore_time_get() + seconds;
+
+ while (1)
+ {
+ LRWKRL(_ecore_thread_global_hash_lock);
+ ret = eina_hash_find(_ecore_thread_global_hash, key);
+ LRWKU(_ecore_thread_global_hash_lock);
+ if ((ret) || (!seconds) || ((seconds > 0) && (tm <= ecore_time_get())))
+ break;
+ LKL(_ecore_thread_global_hash_mutex);
+ CDW(_ecore_thread_global_hash_cond, tm);
+ LKU(_ecore_thread_global_hash_mutex);
+ }
+ if (ret) return ret->data;
+ return NULL;
+#else
+ (void) seconds;
+ return NULL;
+#endif
+}
+
diff --git a/src/lib/ecore/ecore_throttle.c b/src/lib/ecore/ecore_throttle.c
new file mode 100644
index 0000000000..febaeacb77
--- /dev/null
+++ b/src/lib/ecore/ecore_throttle.c
@@ -0,0 +1,104 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static int throttle_val = 0;
+
+/**
+ * @addtogroup Ecore_Throttle_Group Ecore Throttle functions
+ *
+ * @{
+ */
+
+/**
+ * Increase throttle amount
+ *
+ * This will increase or decrease (if @p amount is positive or negative) the
+ * amount of "voluntary throttling" ecore will do to its main loop while
+ * running. This is intended to be used to limit animations and wakeups when
+ * in a strict power management state. The higher the current throttle value
+ * (which can be retrieved by ecore_throttle_get() ), the more throttling
+ * takes place. If the current throttle value is 0, then no throttling takes
+ * place at all.
+ *
+ * The value represents how long the ecore main loop will sleep (in seconds)
+ * before it goes into a fully idle state waiting for events, input or
+ * timing events to wake it up. For example, if the current throttle level
+ * is 0.5, then after every time the main loop cycles and goes into idle
+ * affter processing all events, the main loop will explicitly sleep for 0.5
+ * seconds before sitting and waiting for incoming events or timeouts, thus
+ * preventing animation, async IO and network handling etc. for that period
+ * of time. Of course these events, data and timeouts will be buffered,
+ * thus not losing anything, simply delaying when they get handled by the
+ * throttle value.
+ *
+ * Example:
+ * @code
+ * void enter_powersave(void) {
+ * ecore_throttle_adjust(0.2);
+ * printf("Now at throttle level: %1.3f\n", ecore_throttle_get());
+ * }
+ *
+ * void enter_deep_powersave(void) {
+ * ecore_throttle_adjust(0.5);
+ * printf("Now at throttle level: %1.3f\n", ecore_throttle_get());
+ * }
+ *
+ * void exit_powersave(void) {
+ * ecore_throttle_adjust(-0.2);
+ * printf("Now at throttle level: %1.3f\n", ecore_throttle_get());
+ * }
+ *
+ * void exit_deep_powersave(void) {
+ * ecore_throttle_adjust(-0.5);
+ * printf("Now at throttle level: %1.3f\n", ecore_throttle_get());
+ * }
+ * @endcode
+ *
+ * @param amount Amount (in seconds) to adjust by
+ */
+EAPI void
+ecore_throttle_adjust(double amount)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ int adj = amount * 1000000.0;
+ throttle_val += adj;
+ if (throttle_val < 0) throttle_val = 0;
+}
+
+/**
+ * Get current throttle level
+ *
+ * This gets the current throttling level, which can be adjusted by
+ * ecore_throttle_adjust(). The value is in seconds. Please see
+ * ecore_throttle_adjust() for more information.
+ *
+ * @return The current throttle level
+ */
+EAPI double
+ecore_throttle_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
+ return (double)throttle_val / 1000000.0;
+}
+
+/**
+ * @}
+ */
+
+void
+_ecore_throttle(void)
+{
+ if (throttle_val <= 0) return;
+ usleep(throttle_val);
+}
+
diff --git a/src/lib/ecore/ecore_time.c b/src/lib/ecore/ecore_time.c
new file mode 100644
index 0000000000..44b1dab81f
--- /dev/null
+++ b/src/lib/ecore/ecore_time.c
@@ -0,0 +1,184 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach_time.h>
+#endif
+
+#include <time.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME)
+static clockid_t _ecore_time_clock_id = -1;
+#elif defined(__APPLE__) && defined(__MACH__)
+static double _ecore_time_clock_conversion = 1e-9;
+#endif
+double _ecore_time_loop_time = -1.0;
+
+/**
+ * @addtogroup Ecore_Time_Group
+ *
+ * @{
+ */
+
+/**
+ * Retrieves the current system time as a floating point value in seconds.
+ *
+ * This uses a monotonic clock and thus never goes back in time while
+ * machine is live (even if user changes time or timezone changes,
+ * however it may be reset whenever the machine is restarted).
+ *
+ * @see ecore_loop_time_get().
+ * @see ecore_time_unix_get().
+ *
+ * @return The number of seconds. Start time is not defined (it may be
+ * when the machine was booted, unix time, etc), all it is
+ * defined is that it never goes backwards (unless you got big critical
+ * messages when the application started).
+ */
+EAPI double
+ecore_time_get(void)
+{
+#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME)
+ struct timespec t;
+
+ if (EINA_UNLIKELY(_ecore_time_clock_id < 0))
+ return ecore_time_unix_get();
+
+ if (EINA_UNLIKELY(clock_gettime(_ecore_time_clock_id, &t)))
+ {
+ CRIT("Cannot get current time.");
+ /* Try to at least return the latest value retrieved*/
+ return _ecore_time_loop_time;
+ }
+
+ return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
+#elif defined(HAVE_EVIL)
+ return evil_time_get();
+#elif defined(__APPLE__) && defined(__MACH__)
+ return _ecore_time_clock_conversion * (double)mach_absolute_time();
+#else
+ return ecore_time_unix_get();
+#endif
+}
+
+/**
+ * Retrieves the current UNIX time as a floating point value in seconds.
+ *
+ * @see ecore_time_get().
+ * @see ecore_loop_time_get().
+ *
+ * @return The number of seconds since 12.00AM 1st January 1970.
+ */
+EAPI double
+ecore_time_unix_get(void)
+{
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval timev;
+
+ gettimeofday(&timev, NULL);
+ return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+#else
+# error "Your platform isn't supported yet"
+#endif
+}
+
+/**
+ * Retrieves the time at which the last loop stopped waiting for timeouts or
+ * events.
+ *
+ * This gets the time that the main loop ceased waiting for timouts and/or
+ * events to come in or for signals or any other interrupt source. This should
+ * be considered a reference point for all time based activity that should
+ * calculate its timepoint from the return of ecore_loop_time_get(). Use this
+ * UNLESS you absolutely must get the current actual timepoint - then use
+ * ecore_time_get(). Note that this time is meant to be used as relative to
+ * other times obtained on this run. If you need absolute time references, use
+ * ecore_time_unix_get() instead.
+ *
+ * This function can be called before any loop has ever been run, but either
+ * ecore_init() or ecore_time_get() must have been called once.
+ *
+ * @return The number of seconds. Start time is not defined (it may be
+ * when the machine was booted, unix time, etc), all it is
+ * defined is that it never goes backwards (unless you got big critical
+ * messages when the application started).
+ */
+EAPI double
+ecore_loop_time_get(void)
+{
+ return _ecore_time_loop_time;
+}
+
+/**
+ * @}
+ */
+
+/********************** Internal methods ********************************/
+
+/* TODO: Documentation says "All implementations support the system-wide
+ * real-time clock, which is identified by CLOCK_REALTIME. Check if the fallback
+ * to unix time (without specifying the resolution) might be removed
+ */
+void
+_ecore_time_init(void)
+{
+#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME)
+ struct timespec t;
+
+ if (_ecore_time_clock_id != -1) return;
+
+ if (!clock_gettime(CLOCK_MONOTONIC, &t))
+ {
+ _ecore_time_clock_id = CLOCK_MONOTONIC;
+ DBG("using CLOCK_MONOTONIC.");
+ }
+ else if (!clock_gettime(CLOCK_REALTIME, &t))
+ {
+ /* may go backwards */
+ _ecore_time_clock_id = CLOCK_REALTIME;
+ WRN("CLOCK_MONOTONIC not available. Fallback to CLOCK_REALTIME.");
+ }
+ else
+ {
+ _ecore_time_clock_id = -2;
+ CRIT("Cannot get a valid clock_gettime() clock id! "
+ "Fallback to unix time.");
+ }
+#else
+# ifndef HAVE_EVIL
+# if defined(__APPLE__) && defined(__MACH__)
+ mach_timebase_info_data_t info;
+ kern_return_t err = mach_timebase_info(&info);
+ if (err == 0)
+ {
+ _ecore_time_clock_conversion = 1e-9 * (double)info.numer / (double)info.denom;
+ }
+ else
+ {
+ WRN("Unable to get timebase info. Fallback to nanoseconds.");
+ }
+# else
+# warning "Your platform isn't supported yet"
+ CRIT("Platform does not support clock_gettime. "
+ "Fallback to unix time.");
+# endif
+# endif
+#endif
+
+ _ecore_time_loop_time = ecore_time_get();
+}
+
diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c
new file mode 100644
index 0000000000..768198876b
--- /dev/null
+++ b/src/lib/ecore/ecore_timer.c
@@ -0,0 +1,1015 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <Eo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#define MY_CLASS ECORE_TIMER_CLASS
+#define MY_CLASS_NAME "ecore_timer"
+
+EAPI Eo_Op ECORE_TIMER_BASE_ID = EO_NOOP;
+
+#define ECORE_TIMER_CHECK(obj) \
+ if (!eo_isa((obj), ECORE_TIMER_CLASS)) \
+ return
+
+#ifdef WANT_ECORE_TIMER_DUMP
+# include <string.h>
+# include <execinfo.h>
+# define ECORE_TIMER_DEBUG_BT_NUM 64
+typedef void (*Ecore_Timer_Bt_Func)();
+#endif
+
+struct _Ecore_Timer_Private_Data
+{
+ EINA_INLIST;
+ Ecore_Timer *obj;
+ double in;
+ double at;
+ double pending;
+ Ecore_Task_Cb func;
+ void *data;
+
+#ifdef WANT_ECORE_TIMER_DUMP
+ Ecore_Timer_Bt_Func timer_bt[ECORE_TIMER_DEBUG_BT_NUM];
+ int timer_bt_num;
+#endif
+
+ int references;
+ unsigned char delete_me : 1;
+ unsigned char just_added : 1;
+ unsigned char frozen : 1;
+};
+
+typedef struct _Ecore_Timer_Private_Data Ecore_Timer_Private_Data;
+
+static void _ecore_timer_set(Ecore_Timer *timer,
+ double at,
+ double in,
+ Ecore_Task_Cb func,
+ void *data);
+#ifdef WANT_ECORE_TIMER_DUMP
+static int _ecore_timer_cmp(const void *d1,
+ const void *d2);
+#endif
+
+static int timers_added = 0;
+static int timers_delete_me = 0;
+static Ecore_Timer_Private_Data *timers = NULL;
+static Ecore_Timer_Private_Data *timer_current = NULL;
+static Ecore_Timer_Private_Data *suspended = NULL;
+static double last_check = 0.0;
+static double precision = 10.0 / 1000000.0;
+
+/**
+ * @addtogroup Ecore_Timer_Group
+ *
+ * @{
+ */
+
+/**
+ * Retrieves the current precision used by timer infrastructure.
+ * @return Current precision.
+ * @see ecore_timer_precision_set()
+ */
+EAPI double
+ecore_timer_precision_get(void)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
+ return precision;
+}
+
+/**
+ * @brief Sets the precision to be used by timer infrastructure.
+ *
+ * @param value allowed introduced timeout delay, in seconds.
+ *
+ * This sets the precision for @b all timers. The precision determines how much
+ * of an difference from the requested interval is acceptable. One common reason
+ * to use this function is to @b increase the allowed timeout and thus @b
+ * decrease precision of the timers, this is because less precise the timers
+ * result in the system waking up less often and thus consuming less resources.
+ *
+ * Be aware that kernel may delay delivery even further, these delays
+ * are always possible due other tasks having higher priorities or
+ * other scheduler policies.
+ *
+ * Example:
+ * We have 2 timers, one that expires in a 2.0s and another that
+ * expires in 2.1s, if precision is 0.1s, then the Ecore will request
+ * for the next expire to happen in 2.1s and not 2.0s and another one
+ * of 0.1 as it would before.
+ *
+ * @note Ecore is smart enough to see if there are timers in the
+ * precision range, if it does not, in our example if no second timer
+ * in (T + precision) existed, then it would use the minimum timeout.
+ */
+EAPI void
+ecore_timer_precision_set(double value)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ _ecore_lock();
+
+ if (value < 0.0)
+ {
+ ERR("Precision %f less than zero, ignored", value);
+ goto unlock;
+ }
+ precision = value;
+
+unlock:
+ _ecore_unlock();
+}
+
+/**
+ * Creates a timer to call the given function in the given period of time.
+ * @param in The interval in seconds.
+ * @param func The given function. If @p func returns 1, the timer is
+ * rescheduled for the next interval @p in.
+ * @param data Data to pass to @p func when it is called.
+ * @return A timer object on success. @c NULL on failure.
+ *
+ * This function adds a timer and returns its handle on success and NULL on
+ * failure. The function @p func will be called every @p in seconds. The
+ * function will be passed the @p data pointer as its parameter.
+ *
+ * When the timer @p func is called, it must return a value of either 1
+ * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL).
+ * If it returns 1, it will be called again at the next tick, or if it returns
+ * 0 it will be deleted automatically making any references/handles for it
+ * invalid.
+ */
+EAPI Ecore_Timer *
+ecore_timer_add(double in,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Timer *timer = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ timer = eo_add_custom(MY_CLASS, _ecore_parent, ecore_timer_constructor(in, func, data));
+ eo_unref(timer);
+ return timer;
+}
+
+static Eina_Bool
+_ecore_timer_add(Ecore_Timer *obj,
+ Ecore_Timer_Private_Data *timer,
+ double now,
+ double in,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+
+ if (EINA_UNLIKELY(!eina_main_loop_is()))
+ {
+ eo_error_set(obj);
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
+ }
+
+ timer->obj = obj;
+ eo_do_super(obj, eo_constructor());
+ eo_manual_free_set(obj, EINA_TRUE);
+
+ if (!func)
+ {
+ eo_error_set(obj);
+ ERR("callback function must be set up for an object of class: '%s'", MY_CLASS_NAME);
+ return EINA_FALSE;
+ }
+
+ if (in < 0.0) in = 0.0;
+
+#ifdef WANT_ECORE_TIMER_DUMP
+ timer->timer_bt_num = backtrace((void **)(timer->timer_bt),
+ ECORE_TIMER_DEBUG_BT_NUM);
+#endif
+ _ecore_timer_set(obj, now + in, in, func, (void *)data);
+ return EINA_TRUE;
+}
+
+static void
+_timer_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ double in = va_arg(*list, double);
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+ double now;
+
+ _ecore_lock();
+ now = ecore_time_get();
+
+ Ecore_Timer_Private_Data *timer = _pd;
+ _ecore_timer_add(obj, timer, now, in, func, data);
+ _ecore_unlock();
+}
+
+static void
+_timer_loop_constructor(Eo *obj, void *_pd, va_list *list)
+{
+ double in = va_arg(*list, double);
+ Ecore_Task_Cb func = va_arg(*list, Ecore_Task_Cb);
+ const void *data = va_arg(*list, const void *);
+ double now;
+
+ now = ecore_loop_time_get();
+
+ Ecore_Timer_Private_Data *timer = _pd;
+ _ecore_timer_add(obj, timer, now, in, func, data);
+}
+
+static void
+_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
+{
+ eo_error_set(obj);
+ ERR("only custom constructor can be used with '%s' class", MY_CLASS_NAME);
+}
+
+
+/**
+ * Creates a timer to call the given function in the given period of time.
+ * @param in The interval in seconds from current loop time.
+ * @param func The given function. If @p func returns 1, the timer is
+ * rescheduled for the next interval @p in.
+ * @param data Data to pass to @p func when it is called.
+ * @return A timer object on success. @c NULL on failure.
+ *
+ * This is the same as ecore_timer_add(), but "now" is the time from
+ * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
+ * ecore_timer_add() for more details.
+ */
+EAPI Ecore_Timer *
+ecore_timer_loop_add(double in,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Timer *timer;
+
+ _ecore_lock();
+ timer = _ecore_timer_loop_add(in, func, data);
+ _ecore_unlock();
+
+ return timer;
+}
+
+/**
+ * Delete the specified timer from the timer list.
+ * @param timer The timer to delete.
+ * @return The data pointer set for the timer when @ref ecore_timer_add was
+ * called. @c NULL is returned if the function is unsuccessful.
+ *
+ * Note: @p timer must be a valid handle. If the timer function has already
+ * returned 0, the handle is no longer valid (and does not need to be delete).
+ */
+EAPI void *
+ecore_timer_del(Ecore_Timer *timer)
+{
+ void *data = NULL;
+
+ EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
+ _ecore_lock();
+
+ data = _ecore_timer_del(timer);
+
+ _ecore_unlock();
+ return data;
+}
+
+/**
+ * Change the interval the timer ticks of. If set during
+ * a timer call, this will affect the next interval.
+ *
+ * @param timer The timer to change.
+ * @param in The interval in seconds.
+ */
+EAPI void
+ecore_timer_interval_set(Ecore_Timer *timer,
+ double in)
+{
+ ECORE_TIMER_CHECK(timer);
+ eo_do(timer, ecore_obj_timer_interval_set(in));
+}
+
+static void
+_timer_interval_set(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ double in = va_arg(*list, double);
+ if (in < 0.0) in = 0.0;
+ Ecore_Timer_Private_Data *timer = _pd;
+
+ _ecore_lock();
+ timer->in = in;
+ _ecore_unlock();
+}
+
+/**
+ * Get the interval the timer ticks on.
+ *
+ * @param timer The timer to retrieve the interval from
+ * @return The interval on success. -1 on failure.
+ */
+EAPI double
+ecore_timer_interval_get(Ecore_Timer *timer)
+{
+ double interval = -1.0;
+
+ ECORE_TIMER_CHECK(timer) interval;
+ eo_do(timer, ecore_obj_timer_interval_get(&interval));
+ return interval;
+}
+
+static void
+_timer_interval_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ double *ret = va_arg(*list, double *);
+ *ret = -1.0;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ Ecore_Timer_Private_Data *timer = _pd;
+ _ecore_lock();
+ *ret = timer->in;
+ _ecore_unlock();
+}
+
+/**
+ * Add some delay for the next occurrence of a timer.
+ * This doesn't affect the interval of a timer.
+ *
+ * @param timer The timer to change.
+ * @param add The delay to add to the next iteration.
+ */
+EAPI void
+ecore_timer_delay(Ecore_Timer *timer,
+ double add)
+{
+ ECORE_TIMER_CHECK(timer);
+ eo_do(timer, ecore_obj_timer_delay(add));
+}
+
+static void
+_timer_delay(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
+{
+ double add = va_arg(*list, double);
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ _ecore_lock();
+ _ecore_timer_delay(obj, add);
+ _ecore_unlock();
+}
+
+/**
+ * Reset a timer to its full interval
+ * This doesn't affect the interval of a timer
+ * @param timer The timer
+ * @since 1.2
+ * @note This is equivalent to (but faster than)
+ * @code
+ * ecore_timer_delay(timer, ecore_timer_interval_get(timer) - ecore_timer_pending_get(timer));
+ * @endcode
+ */
+EAPI void
+ecore_timer_reset(Ecore_Timer *timer)
+{
+ ECORE_TIMER_CHECK(timer);
+ eo_do(timer, ecore_obj_timer_reset());
+}
+
+static void
+_timer_reset(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ double now, add;
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ Ecore_Timer_Private_Data *timer = _pd;
+
+ _ecore_lock();
+ now = ecore_time_get();
+
+ if (timer->frozen)
+ add = timer->pending;
+ else
+ add = timer->at - now;
+ _ecore_timer_delay(obj, timer->in - add);
+ _ecore_unlock();
+}
+
+/**
+ * Get the pending time regarding a timer.
+ *
+ * @param timer The timer to learn from.
+ * @return The pending time.
+ * @ingroup Ecore_Timer_Group
+ */
+EAPI double
+ecore_timer_pending_get(Ecore_Timer *timer)
+{
+ double ret = 0.0;
+
+ ECORE_TIMER_CHECK(timer) ret;
+ eo_do(timer, ecore_obj_timer_pending_get(&ret));
+ return ret;
+}
+
+static void
+_timer_pending_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+ double now;
+ double *ret = va_arg(*list, double *);
+ *ret = 0.0;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ _ecore_lock();
+ Ecore_Timer_Private_Data *timer = _pd;
+
+ now = ecore_time_get();
+
+ if (timer->frozen)
+ *ret = timer->pending;
+ else
+ *ret = timer->at - now;
+ _ecore_unlock();
+}
+/**
+ * Pauses a running timer.
+ *
+ * @param timer The timer to be paused.
+ *
+ * The timer callback won't be called while the timer is paused. The remaining
+ * time until the timer expires will be saved, so the timer can be resumed with
+ * that same remaining time to expire, instead of expiring instantly. Use
+ * ecore_timer_thaw() to resume it.
+ *
+ * @note Nothing happens if the timer was already paused.
+ *
+ * @see ecore_timer_thaw()
+ */
+EAPI void
+ecore_timer_freeze(Ecore_Timer *timer)
+{
+ ECORE_TIMER_CHECK(timer);
+ eo_do(timer, eo_event_freeze());
+}
+
+static void
+_timer_freeze(Eo *obj EINA_UNUSED, void *_pd, va_list *list EINA_UNUSED)
+{
+ double now;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+
+ Ecore_Timer_Private_Data *timer = _pd;
+ _ecore_lock();
+
+ /* Timer already frozen */
+ if (timer->frozen)
+ goto unlock;
+
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+ suspended = (Ecore_Timer_Private_Data *)eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+
+ now = ecore_time_get();
+
+ timer->pending = timer->at - now;
+ timer->at = 0.0;
+ timer->frozen = 1;
+unlock:
+ _ecore_unlock();
+}
+
+/**
+ * Resumes a frozen (paused) timer.
+ *
+ * @param timer The timer to be resumed.
+ *
+ * The timer will be resumed from its previous relative position in time. That
+ * means, if it had X seconds remaining until expire when it was paused, it will
+ * be started now with those same X seconds remaining to expire again. But
+ * notice that the interval time won't be touched by this call or by
+ * ecore_timer_freeze().
+ *
+ * @see ecore_timer_freeze()
+ */
+EAPI void
+ecore_timer_thaw(Ecore_Timer *timer)
+{
+ ECORE_TIMER_CHECK(timer);
+ eo_do(timer, eo_event_thaw());
+}
+
+static void
+_timer_thaw(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ double now;
+
+ EINA_MAIN_LOOP_CHECK_RETURN;
+ Ecore_Timer_Private_Data *timer = _pd;
+
+ _ecore_lock();
+
+ /* Timer not frozen */
+ if (!timer->frozen)
+ goto unlock;
+
+ suspended = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+ now = ecore_time_get();
+
+ _ecore_timer_set(obj, timer->pending + now, timer->in, timer->func, timer->data);
+unlock:
+ _ecore_unlock();
+}
+
+EAPI char *
+ecore_timer_dump(void)
+{
+#ifdef WANT_ECORE_TIMER_DUMP
+ Eina_Strbuf *result;
+ char *out;
+ Ecore_Timer *tm;
+ Eina_List *tmp = NULL;
+ int living_timer = 0;
+ int unknow_timer = 0;
+
+ EINA_MAIN_LOOP_CHECK_RETURN(NULL);
+ _ecore_lock();
+ result = eina_strbuf_new();
+
+ EINA_INLIST_FOREACH(timers, tm)
+ tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm);
+
+ EINA_LIST_FREE(tmp, tm)
+ {
+ char **strings;
+ int j;
+
+ if (!tm->frozen && !tm->delete_me)
+ living_timer++;
+
+ strings = backtrace_symbols((void **)tm->timer_bt, tm->timer_bt_num);
+ if (tm->timer_bt_num <= 0 || strings == NULL)
+ {
+ unknow_timer++;
+ continue;
+ }
+
+ eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in);
+ if (tm->frozen)
+ eina_strbuf_append(result, "FROZEN\n");
+ if (tm->delete_me)
+ eina_strbuf_append(result, "DELETED\n");
+ for (j = 0; j < tm->timer_bt_num; j++)
+ eina_strbuf_append_printf(result, "%s\n", strings[j]);
+
+ free(strings);
+ }
+
+ eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer);
+
+ out = eina_strbuf_string_steal(result);
+ eina_strbuf_free(result);
+ _ecore_unlock();
+
+ return out;
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * @}
+ */
+
+Ecore_Timer *
+_ecore_timer_loop_add(double in,
+ Ecore_Task_Cb func,
+ const void *data)
+{
+ Ecore_Timer *timer = NULL;
+ timer = eo_add_custom(MY_CLASS, _ecore_parent, ecore_timer_loop_constructor(in, func, data));
+ eo_unref(timer);
+
+ return timer;
+}
+
+EAPI void
+_ecore_timer_delay(Ecore_Timer *obj,
+ double add)
+{
+ Ecore_Timer_Private_Data *timer = eo_data_get(obj, MY_CLASS);
+
+ if (timer->frozen)
+ {
+ timer->pending += add;
+ }
+ else
+ {
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+ _ecore_timer_set(obj, timer->at + add, timer->in, timer->func, timer->data);
+ }
+}
+
+void *
+_ecore_timer_del(Ecore_Timer *obj)
+{
+ Ecore_Timer_Private_Data *timer = eo_data_get(obj, MY_CLASS);
+
+ if (timer->frozen && !timer->references)
+ {
+ void *data = timer->data;
+
+ suspended = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+
+ if (timer->delete_me)
+ timers_delete_me--;
+
+ eo_parent_set(obj, NULL);
+
+ if (eo_destructed_is(obj))
+ eo_manual_free(obj);
+ else
+ eo_manual_free_set(obj, EINA_FALSE);
+ return data;
+ }
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
+ timer->delete_me = 1;
+ timers_delete_me++;
+ return timer->data;
+}
+
+static void
+_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
+{
+ Ecore_Timer_Private_Data *pd = _pd;
+
+ if (!pd->delete_me)
+ {
+ pd->delete_me = 1;
+ timers_delete_me++;
+ }
+
+ eo_do_super(obj, eo_destructor());
+}
+
+void
+_ecore_timer_shutdown(void)
+{
+ Ecore_Timer_Private_Data *timer;
+
+ while ((timer = timers))
+ {
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers));
+
+ eo_parent_set(timer->obj, NULL);
+ if (eo_destructed_is(timer->obj))
+ eo_manual_free(timer->obj);
+ else
+ eo_manual_free_set(timer->obj, EINA_FALSE);
+ }
+
+ while ((timer = suspended))
+ {
+ suspended = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
+
+ eo_parent_set(timer->obj, NULL);
+ if (eo_destructed_is(timer->obj))
+ eo_manual_free(timer->obj);
+ else
+ eo_manual_free_set(timer->obj, EINA_FALSE);
+ }
+
+ timer_current = NULL;
+}
+
+void
+_ecore_timer_cleanup(void)
+{
+ Ecore_Timer_Private_Data *l;
+ int in_use = 0, todo = timers_delete_me, done = 0;
+
+ if (!timers_delete_me) return;
+ for (l = timers; l; )
+ {
+ Ecore_Timer_Private_Data *timer = l;
+
+ l = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (timer->delete_me)
+ {
+ if (timer->references)
+ {
+ in_use++;
+ continue;
+ }
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+
+ eo_parent_set(timer->obj, NULL);
+ if (eo_destructed_is(timer->obj))
+ eo_manual_free(timer->obj);
+ else
+ eo_manual_free_set(timer->obj, EINA_FALSE);
+ timers_delete_me--;
+ done++;
+ if (timers_delete_me == 0) return;
+ }
+ }
+ for (l = suspended; l; )
+ {
+ Ecore_Timer_Private_Data *timer = l;
+
+ l = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(l)->next;
+ if (timer->delete_me)
+ {
+ if (timer->references)
+ {
+ in_use++;
+ continue;
+ }
+ suspended = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+
+ eo_parent_set(timer->obj, NULL);
+ if (eo_destructed_is(timer->obj))
+ eo_manual_free(timer->obj);
+ else
+ eo_manual_free_set(timer->obj, EINA_FALSE);
+ timers_delete_me--;
+ done++;
+ if (timers_delete_me == 0) return;
+ }
+ }
+
+ if ((!in_use) && (timers_delete_me))
+ {
+ ERR("%d timers to delete, but they were not found!"
+ "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
+ "reset counter.",
+ timers_delete_me, todo, done, todo - done, in_use);
+ timers_delete_me = 0;
+ }
+}
+
+void
+_ecore_timer_enable_new(void)
+{
+ Ecore_Timer_Private_Data *timer;
+
+ if (!timers_added) return;
+ timers_added = 0;
+ EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
+}
+
+int
+_ecore_timers_exists(void)
+{
+ Ecore_Timer_Private_Data *timer = timers;
+
+ while ((timer) && (timer->delete_me))
+ timer = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer)->next;
+
+ return !!timer;
+}
+
+static inline Ecore_Timer *
+_ecore_timer_first_get(void)
+{
+ Ecore_Timer *ret = NULL;
+ Ecore_Timer_Private_Data *timer = timers;
+
+ while ((timer) && ((timer->delete_me) || (timer->just_added)))
+ timer = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer)->next;
+
+ if (timer)
+ ret = timer->obj;
+ return ret;
+}
+
+static inline Ecore_Timer *
+_ecore_timer_after_get(Ecore_Timer *obj)
+{
+ Ecore_Timer *ret = NULL;
+ Ecore_Timer_Private_Data *base = eo_data_get(obj, MY_CLASS);
+
+ Ecore_Timer_Private_Data *timer = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(base)->next;
+ Ecore_Timer_Private_Data *valid_timer = NULL;
+ double maxtime = base->at + precision;
+
+ while ((timer) && (timer->at < maxtime))
+ {
+ if (!((timer->delete_me) || (timer->just_added)))
+ valid_timer = timer;
+ timer = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer)->next;
+ }
+
+ if (valid_timer)
+ ret = valid_timer->obj;
+ return ret;
+}
+
+double
+_ecore_timer_next_get(void)
+{
+ double now;
+ double in;
+ Ecore_Timer *first_obj, *second_obj;
+ Ecore_Timer_Private_Data *first;
+
+ first_obj = _ecore_timer_first_get();
+ if (!first_obj) return -1;
+
+ second_obj = _ecore_timer_after_get(first_obj);
+ if (second_obj) first_obj = second_obj;
+
+ first = eo_data_get(first_obj, MY_CLASS);
+
+ now = ecore_loop_time_get();
+ in = first->at - now;
+ if (in < 0) in = 0;
+ return in;
+}
+
+static inline void
+_ecore_timer_reschedule(Ecore_Timer *obj,
+ double when)
+{
+ Ecore_Timer_Private_Data *timer = eo_data_get(obj, MY_CLASS);
+ if ((timer->delete_me) || (timer->frozen)) return;
+
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+
+ /* if the timer would have gone off more than 15 seconds ago,
+ * assume that the system hung and set the timer to go off
+ * timer->in from now. this handles system hangs, suspends
+ * and more, so ecore will only "replay" the timers while
+ * the system is suspended if it is suspended for less than
+ * 15 seconds (basically). this also handles if the process
+ * is stopped in a debugger or IO and other handling gets
+ * really slow within the main loop.
+ */
+ if ((timer->at + timer->in) < (when - 15.0))
+ _ecore_timer_set(obj, when + timer->in, timer->in, timer->func, timer->data);
+ else
+ _ecore_timer_set(obj, timer->at + timer->in, timer->in, timer->func, timer->data);
+}
+
+/* assume that we hold the ecore lock when entering this function */
+void
+_ecore_timer_expired_timers_call(double when)
+{
+ /* call the first expired timer until no expired timers exist */
+ while (_ecore_timer_expired_call(when)) ;
+}
+
+/* assume that we hold the ecore lock when entering this function */
+int
+_ecore_timer_expired_call(double when)
+{
+ if (!timers) return 0;
+ if (last_check > when)
+ {
+ Ecore_Timer_Private_Data *timer;
+ /* User set time backwards */
+ EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
+ }
+ last_check = when;
+
+ if (!timer_current)
+ {
+ /* regular main loop, start from head */
+ timer_current = timers;
+ }
+ else
+ {
+ /* recursive main loop, continue from where we were */
+ Ecore_Timer_Private_Data *timer_old = timer_current;
+ timer_current = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer_current)->next;
+ _ecore_timer_reschedule(timer_old->obj, when);
+ }
+
+ while (timer_current)
+ {
+ Ecore_Timer_Private_Data *timer = timer_current;
+
+ if (timer->at > when)
+ {
+ timer_current = NULL; /* ended walk, next should restart. */
+ return 0;
+ }
+
+ if ((timer->just_added) || (timer->delete_me))
+ {
+ timer_current = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer_current)->next;
+ continue;
+ }
+
+ timer->references++;
+ if (!_ecore_call_task_cb(timer->func, timer->data))
+ {
+ if (!timer->delete_me) _ecore_timer_del(timer->obj);
+ }
+ timer->references--;
+
+ if (timer_current) /* may have changed in recursive main loops */
+ timer_current = (Ecore_Timer_Private_Data *)EINA_INLIST_GET(timer_current)->next;
+
+ _ecore_timer_reschedule(timer->obj, when);
+ }
+ return 0;
+}
+
+static void
+_ecore_timer_set(Ecore_Timer *obj,
+ double at,
+ double in,
+ Ecore_Task_Cb func,
+ void *data)
+{
+ Ecore_Timer_Private_Data *t2;
+
+ Ecore_Timer_Private_Data *timer = eo_data_get(obj, MY_CLASS);
+
+ timers_added = 1;
+ timer->at = at;
+ timer->in = in;
+ timer->func = func;
+ timer->data = data;
+ timer->just_added = 1;
+ timer->frozen = 0;
+ timer->pending = 0.0;
+ if (timers)
+ {
+ EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
+ {
+ if (timer->at > t2->at)
+ {
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2));
+ return;
+ }
+ }
+ }
+ timers = (Ecore_Timer_Private_Data *)eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+}
+
+#ifdef WANT_ECORE_TIMER_DUMP
+static int
+_ecore_timer_cmp(const void *d1,
+ const void *d2)
+{
+ const Ecore_Timer *t1 = d1;
+ const Ecore_Timer *t2 = d2;
+
+ return (int)((t1->in - t2->in) * 100);
+}
+#endif
+
+static void
+_class_constructor(Eo_Class *klass)
+{
+ const Eo_Op_Func_Description func_desc[] = {
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_CONSTRUCTOR), _timer_constructor),
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_LOOP_CONSTRUCTOR), _timer_loop_constructor),
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_INTERVAL_SET), _timer_interval_set),
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_INTERVAL_GET), _timer_interval_get),
+
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_FREEZE), _timer_freeze),
+ EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_THAW), _timer_thaw),
+
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_DELAY), _timer_delay),
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_RESET), _timer_reset),
+ EO_OP_FUNC(ECORE_TIMER_ID(ECORE_TIMER_SUB_ID_PENDING_GET), _timer_pending_get),
+ EO_OP_FUNC_SENTINEL
+ };
+
+ eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_CONSTRUCTOR, "Creates a timer to call the given function in the given period of time."),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_LOOP_CONSTRUCTOR, "Creates a timer to call the given function in the given period of time."),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_INTERVAL_SET, "Change the interval the timer ticks of."),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_INTERVAL_GET, "Get the interval the timer ticks on."),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_DELAY, "Add some delay for the next occurrence of a timer."),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_RESET, "Reset a timer to its full interval"),
+ EO_OP_DESCRIPTION(ECORE_TIMER_SUB_ID_PENDING_GET, "Get the pending time regarding a timer."),
+ EO_OP_DESCRIPTION_SENTINEL
+};
+static const Eo_Class_Description class_desc = {
+ EO_VERSION,
+ MY_CLASS_NAME,
+ EO_CLASS_TYPE_REGULAR,
+ EO_CLASS_DESCRIPTION_OPS(&ECORE_TIMER_BASE_ID, op_desc, ECORE_TIMER_SUB_ID_LAST),
+ NULL,
+ sizeof(Ecore_Timer_Private_Data),
+ _class_constructor,
+ NULL
+};
+
+EO_DEFINE_CLASS(ecore_timer_class_get, &class_desc, EO_BASE_CLASS, NULL)
diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa.h b/src/lib/ecore_cocoa/Ecore_Cocoa.h
new file mode 100644
index 0000000000..51c8ead21b
--- /dev/null
+++ b/src/lib/ecore_cocoa/Ecore_Cocoa.h
@@ -0,0 +1,147 @@
+#ifndef __ECORE_COCOA_H__
+#define __ECORE_COCOA_H__
+
+/*
+ * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND
+ * THE API MAY CHANGE.
+ */
+
+#ifndef ECORE_COCOA_WIP_GNSIDNQI
+# warning "You are using a work in progress API. This API is not stable"
+# warning "and is subject to change. You use this at your own risk."
+#endif
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+#else
+# define EAPI
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _Ecore_Cocoa_Window Ecore_Cocoa_Window;
+
+EAPI extern int ECORE_COCOA_EVENT_GOT_FOCUS;
+EAPI extern int ECORE_COCOA_EVENT_LOST_FOCUS;
+EAPI extern int ECORE_COCOA_EVENT_RESIZE;
+EAPI extern int ECORE_COCOA_EVENT_EXPOSE;
+
+typedef struct _Ecore_Cocoa_Event_Video_Resize Ecore_Cocoa_Event_Video_Resize;
+struct _Ecore_Cocoa_Event_Video_Resize
+{
+ int w;
+ int h;
+};
+
+
+/* Core */
+
+EAPI int ecore_cocoa_init(void);
+EAPI int ecore_cocoa_shutdown(void);
+EAPI void ecore_cocoa_feed_events(void);
+
+/* Window */
+
+EAPI Ecore_Cocoa_Window *ecore_cocoa_window_new(int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_cocoa_window_free(Ecore_Cocoa_Window *window);
+
+EAPI void *ecore_cocoa_window_hwnd_get(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_move(Ecore_Cocoa_Window *window,
+ int x,
+ int y);
+
+EAPI void ecore_cocoa_window_resize(Ecore_Cocoa_Window *window,
+ int width,
+ int height);
+
+EAPI void ecore_cocoa_window_move_resize(Ecore_Cocoa_Window *window,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_cocoa_window_geometry_get(Ecore_Cocoa_Window *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height);
+
+EAPI void ecore_cocoa_window_size_get(Ecore_Cocoa_Window *window,
+ int *width,
+ int *height);
+
+EAPI void ecore_cocoa_window_size_min_set(Ecore_Cocoa_Window *window,
+ unsigned int min_width,
+ unsigned int min_height);
+
+EAPI void ecore_cocoa_window_size_min_get(Ecore_Cocoa_Window *window,
+ unsigned int *min_width,
+ unsigned int *min_height);
+
+EAPI void ecore_cocoa_window_size_max_set(Ecore_Cocoa_Window *window,
+ unsigned int max_width,
+ unsigned int max_height);
+
+EAPI void ecore_cocoa_window_size_max_get(Ecore_Cocoa_Window *window,
+ unsigned int *max_width,
+ unsigned int *max_height);
+
+EAPI void ecore_cocoa_window_size_base_set(Ecore_Cocoa_Window *window,
+ unsigned int base_width,
+ unsigned int base_height);
+
+EAPI void ecore_cocoa_window_size_base_get(Ecore_Cocoa_Window *window,
+ unsigned int *base_width,
+ unsigned int *base_height);
+
+EAPI void ecore_cocoa_window_size_step_set(Ecore_Cocoa_Window *window,
+ unsigned int step_width,
+ unsigned int step_height);
+
+EAPI void ecore_cocoa_window_size_step_get(Ecore_Cocoa_Window *window,
+ unsigned int *step_width,
+ unsigned int *step_height);
+
+EAPI void ecore_cocoa_window_show(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_hide(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_raise(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_lower(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_title_set(Ecore_Cocoa_Window *window,
+ const char *title);
+
+EAPI void ecore_cocoa_window_focus_set(Ecore_Cocoa_Window *window);
+
+EAPI void ecore_cocoa_window_iconified_set(Ecore_Cocoa_Window *window,
+ int on);
+
+EAPI void ecore_cocoa_window_borderless_set(Ecore_Cocoa_Window *window,
+ int on);
+
+EAPI void ecore_cocoa_window_view_set(Ecore_Cocoa_Window *window,
+ void *view);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h b/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h
new file mode 100644
index 0000000000..7068bc22a8
--- /dev/null
+++ b/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h
@@ -0,0 +1,285 @@
+#ifndef ECORE_COCOA_KEYS_H__
+#define ECORE_COCOA_KEYS_H__
+
+struct _ecore_cocoa_keys_s
+{
+ int code;
+ const char *name;
+ const char *compose;
+};
+
+static const struct _ecore_cocoa_keys_s keystable[] =
+{
+
+{ 0, "0x00", "" },
+{ 0, "First", "" },
+{ 3, "Return", "\015" },
+{ 8, "BackSpace", "\010" },
+{ 9, "Tab", "\011" },
+{ 12, "Clear", "" },
+{ 13, "Return", "\015" },
+{ 19, "Pause", "" },
+{ 25, "BackTab", ""},
+{ 27, "Escape", "" },
+{ 32, "space", " " },
+{ 33, "exclam", "!" },
+{ 34, "quotedbl", "\"" },
+{ 35, "numbersign", "#" },
+{ 36, "dollar", "$" },
+{ 37, "percent", "%%" },
+{ 38, "ampersand", "&" },
+{ 39, "apostrophe", "'" },
+{ 40, "parenleft", "(" },
+{ 41, "parenright", ")" },
+{ 42, "asterisk", "*" },
+{ 43, "plus", "+" },
+{ 44, "comma", "," },
+{ 45, "minus", "-" },
+{ 46, "period", "." },
+{ 47, "slash", "/" },
+{ 48, "0", "0" },
+{ 49, "1", "1" },
+{ 50, "2", "2" },
+{ 51, "3", "3" },
+{ 52, "4", "4" },
+{ 53, "5", "5" },
+{ 54, "6", "6" },
+{ 55, "7", "7" },
+{ 56, "8", "8" },
+{ 57, "9", "9" },
+{ 58, "colon", ";" },
+{ 59, "semicolon", ";" },
+{ 60, "less", "<" },
+{ 61, "equal", "=" },
+{ 62, "greater", ">" },
+{ 63, "question", "?" },
+{ 64, "at", "@" },
+
+{ 91, "bracketleft", "[" },
+{ 92, "backslash", "\\" },
+{ 93, "bracketright", "]" },
+{ 94, "asciicircumm", "^" },
+{ 95, "underscore", "_" },
+{ 96, "backquote", "`" },
+{ 97, "a", "a" },
+{ 98, "b", "b" },
+{ 99, "c", "c" },
+{ 100, "d", "d" },
+{ 101, "e", "e" },
+{ 102, "f", "f" },
+{ 103, "g", "g" },
+{ 104, "h", "h" },
+{ 105, "i", "i" },
+{ 106, "j", "j" },
+{ 107, "k", "k" },
+{ 108, "l", "l" },
+{ 109, "m", "m" },
+{ 110, "n", "n" },
+{ 111, "o", "o" },
+{ 112, "p", "p" },
+{ 113, "q", "q" },
+{ 114, "r", "r" },
+{ 115, "s", "s" },
+{ 116, "t", "t" },
+{ 117, "u", "u" },
+{ 118, "v", "v" },
+{ 119, "w", "w" },
+{ 120, "x", "x" },
+{ 121, "y", "y" },
+{ 122, "z", "z" },
+{ 123, "braceleft", "" },
+{ 124, "pipe", "" },
+{ 125, "braceright", "" },
+{ 127, "Delete", "\177" },
+{ 126, "asciitilde", "~" },
+
+{ 160, "w0", "" },
+{ 161, "w1", "" },
+{ 162, "w2", "" },
+{ 163, "w3", "" },
+{ 164, "w4", "" },
+{ 165, "w5", "" },
+{ 166, "w6", "" },
+{ 167, "w7", "" },
+{ 168, "w8", "" },
+{ 169, "w9", "" },
+{ 170, "w10", "" },
+{ 171, "w11", "" },
+{ 172, "w12", "" },
+{ 173, "w13", "" },
+{ 174, "w14", "" },
+{ 175, "w15", "" },
+{ 176, "w16", "" },
+{ 177, "w17", "" },
+{ 178, "w18", "" },
+{ 179, "w19", "" },
+{ 180, "w20", "" },
+{ 181, "w21", "" },
+{ 182, "w22", "" },
+{ 183, "w23", "" },
+{ 184, "w24", "" },
+{ 185, "w25", "" },
+{ 186, "w26", "" },
+{ 187, "w27", "" },
+{ 188, "w28", "" },
+{ 189, "w29", "" },
+{ 190, "w30", "" },
+{ 191, "w31", "" },
+{ 192, "w32", "" },
+{ 193, "w33", "" },
+{ 194, "w34", "" },
+{ 195, "w35", "" },
+{ 196, "w36", "" },
+{ 197, "w37", "" },
+{ 198, "w38", "" },
+{ 199, "w39", "" },
+{ 200, "w40", "" },
+{ 201, "w41", "" },
+{ 202, "w42", "" },
+{ 203, "w43", "" },
+{ 204, "w44", "" },
+{ 205, "w45", "" },
+{ 206, "w46", "" },
+{ 207, "w47", "" },
+{ 208, "w48", "" },
+{ 209, "w49", "" },
+{ 210, "w50", "" },
+{ 211, "w51", "" },
+{ 212, "w52", "" },
+{ 213, "w53", "" },
+{ 214, "w54", "" },
+{ 215, "w55", "" },
+{ 216, "w56", "" },
+{ 217, "w57", "" },
+{ 218, "w58", "" },
+{ 219, "w59", "" },
+{ 220, "w60", "" },
+{ 221, "w61", "" },
+{ 222, "w62", "" },
+{ 223, "w63", "" },
+{ 224, "w64", "" },
+{ 225, "w65", "" },
+{ 226, "w66", "" },
+{ 227, "w67", "" },
+{ 228, "w68", "" },
+{ 229, "w69", "" },
+{ 230, "w70", "" },
+{ 231, "w71", "" },
+{ 232, "w72", "" },
+{ 233, "w73", "" },
+{ 234, "w74", "" },
+{ 235, "w75", "" },
+{ 236, "w76", "" },
+{ 237, "w77", "" },
+{ 238, "w78", "" },
+{ 239, "w79", "" },
+{ 240, "w80", "" },
+{ 241, "w81", "" },
+{ 242, "w82", "" },
+{ 243, "w83", "" },
+{ 244, "w84", "" },
+{ 245, "w85", "" },
+{ 246, "w86", "" },
+{ 247, "w87", "" },
+{ 248, "w88", "" },
+{ 249, "w89", "" },
+{ 250, "w90", "" },
+{ 251, "w91", "" },
+{ 252, "w92", "" },
+{ 253, "w93", "" },
+{ 254, "w94", "" },
+{ 255, "w95", "" },
+
+{ 256, "KP0", "0" },
+{ 257, "KP1", "1" },
+{ 258, "KP2", "2" },
+{ 259, "KP3", "3" },
+{ 260, "KP4", "4" },
+{ 261, "KP5", "5" },
+{ 262, "KP6", "6" },
+{ 263, "KP7", "7" },
+{ 264, "KP8", "8" },
+{ 265, "KP9", "9" },
+{ 266, "period", "." },
+{ 267, "KP_Divide", "/" },
+{ 268, "KP_Multiply", "*" },
+{ 269, "KP_Minus", "-" },
+{ 270, "KP_Plus", "+" },
+{ 271, "KP_Enter", "\015" },
+{ 272, "KP_Equals", "=" },
+
+{ NSUpArrowFunctionKey, "Up", "" },
+{ NSDownArrowFunctionKey, "Down", "" },
+{ NSRightArrowFunctionKey, "Right", "" },
+{ NSLeftArrowFunctionKey, "Left", "" },
+{ NSInsertFunctionKey, "Insert", "" },
+{ NSHomeFunctionKey, "Home", "" },
+{ NSEndFunctionKey, "End", "" },
+{ NSPageUpFunctionKey, "Page_Up", "" },
+{ NSPageDownFunctionKey, "Page_Down", "" },
+
+{ NSF1FunctionKey, "F1", "" },
+{ NSF2FunctionKey, "F2", "" },
+{ NSF3FunctionKey, "F3", "" },
+{ NSF4FunctionKey, "F4", "" },
+{ NSF5FunctionKey, "F5", "" },
+{ NSF6FunctionKey, "F6", "" },
+{ NSF7FunctionKey, "F7", "" },
+{ NSF8FunctionKey, "F8", "" },
+{ NSF9FunctionKey, "F9", "" },
+{ NSF10FunctionKey, "F10", "" },
+{ NSF11FunctionKey, "F11", "" },
+{ NSF12FunctionKey, "F12", "" },
+{ NSF13FunctionKey, "F13", "" },
+{ NSF14FunctionKey, "F14", "" },
+{ NSF15FunctionKey, "F15", "" },
+{ NSF16FunctionKey, "F16", "" },
+{ NSF17FunctionKey, "F17", "" },
+{ NSF18FunctionKey, "F18", "" },
+{ NSF19FunctionKey, "F19", "" },
+{ NSF20FunctionKey, "F20", "" },
+{ NSF21FunctionKey, "F21", "" },
+{ NSF22FunctionKey, "F22", "" },
+{ NSF23FunctionKey, "F23", "" },
+{ NSF24FunctionKey, "F24", "" },
+{ NSF25FunctionKey, "F25", "" },
+{ NSF26FunctionKey, "F26", "" },
+{ NSF27FunctionKey, "F27", "" },
+{ NSF28FunctionKey, "F28", "" },
+{ NSF29FunctionKey, "F29", "" },
+{ NSF30FunctionKey, "F30", "" },
+{ NSF31FunctionKey, "F31", "" },
+{ NSF32FunctionKey, "F32", "" },
+{ NSF33FunctionKey, "F33", "" },
+{ NSF34FunctionKey, "F34", "" },
+{ NSF35FunctionKey, "F35", "" },
+
+{ NSClearLineFunctionKey, "Num_Lock", "" },
+{ 301, "Caps_Lock", "" },
+{ NSScrollLockFunctionKey, "Scroll_Lock", "" },
+{ 303, "Shift_R", "" },
+{ 304, "Shift_L", "" },
+{ 305, "Control_R", "" },
+{ 306, "Control_L", "" },
+{ 307, "Alt_R", "" },
+{ 308, "Alt_L", "" },
+{ 309, "Meta_R", "" },
+{ 310, "Meta_L", "" },
+{ 311, "Super_L", "" },
+{ 312, "Super_R", "" },
+
+{ NSModeSwitchFunctionKey, "Mode", "" },
+{ 314, "Compose", "" },
+
+{ NSHelpFunctionKey, "Help", "" },
+{ NSPrintFunctionKey, "Print", "" },
+{ NSSysReqFunctionKey, "SysReq", "" },
+{ NSBreakFunctionKey, "Break", "" },
+{ NSMenuFunctionKey, "Menu", "" },
+{ 320, "Power", "" },
+{ 321, "Euro", "" },
+{ NSUndoFunctionKey, "Undo", "" }
+
+};
+
+#endif /* ECORE_COCOA_KEYS_H__ */
diff --git a/src/lib/ecore_cocoa/ecore_cocoa.m b/src/lib/ecore_cocoa/ecore_cocoa.m
new file mode 100644
index 0000000000..3f6023af1f
--- /dev/null
+++ b/src/lib/ecore_cocoa/ecore_cocoa.m
@@ -0,0 +1,283 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Cocoa/Cocoa.h>
+
+#include <Eina.h>
+
+#include <Ecore.h>
+#include <ecore_private.h>
+#include <Ecore_Input.h>
+
+#include "Ecore_Cocoa.h"
+#include "Ecore_Cocoa_Keys.h"
+
+
+EAPI int ECORE_COCOA_EVENT_GOT_FOCUS = 0;
+EAPI int ECORE_COCOA_EVENT_LOST_FOCUS = 0;
+EAPI int ECORE_COCOA_EVENT_RESIZE = 0;
+EAPI int ECORE_COCOA_EVENT_EXPOSE = 0;
+
+static int _ecore_cocoa_init_count = 0;
+
+static int old_flags;
+
+EAPI int
+ecore_cocoa_init(void)
+{
+ if (++_ecore_cocoa_init_count != 1)
+ return _ecore_cocoa_init_count;
+
+ if (!ecore_event_init())
+ return --_ecore_cocoa_init_count;
+
+ NSApplicationLoad();
+
+ ECORE_COCOA_EVENT_GOT_FOCUS = ecore_event_type_new();
+ ECORE_COCOA_EVENT_LOST_FOCUS = ecore_event_type_new();
+ ECORE_COCOA_EVENT_RESIZE = ecore_event_type_new();
+ ECORE_COCOA_EVENT_EXPOSE = ecore_event_type_new();
+
+ return _ecore_cocoa_init_count;
+}
+
+/**
+ * Shuts down the Ecore_Cocoa library.
+ * @return @c The number of times the system has been initialised without
+ * being shut down.
+ * @ingroup Ecore_Cocoa_Library_Group
+ */
+EAPI int
+ecore_cocoa_shutdown(void)
+{
+ if (--_ecore_cocoa_init_count != 0)
+ return _ecore_cocoa_init_count;
+
+ ecore_event_shutdown();
+
+ return _ecore_cocoa_init_count;
+}
+
+EAPI void
+ecore_cocoa_feed_events(void)
+{
+ NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0.001];
+ NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:date
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ [date release];
+ if (!event) return; // SDL loops until null; maybe we should do that too. or not.
+
+ unsigned int time = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff);
+
+ switch([event type])
+ {
+ case NSMouseMoved:
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ {
+ Ecore_Event_Mouse_Move * ev = calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!ev) return;
+ ev->x = [event locationInWindow].x;
+ ev->y = [event locationInWindow].y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->timestamp = time;
+ ev->window = [event window];
+ ev->modifiers = 0; /* FIXME: keep modifier around. */
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+
+ [NSApp sendEvent:event]; // pass along mouse events, for window manager
+ break;
+ }
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ {
+ Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!ev) return;
+ ev->x = [event locationInWindow].x;
+ ev->y = [event locationInWindow].y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->timestamp = time;
+ ev->buttons = [event buttonNumber] + 1; // Apple indexes buttons from 0
+
+ if ([event clickCount] == 2)
+ ev->double_click = 1;
+ else
+ ev->double_click = 0;
+
+ if ([event clickCount] >= 3)
+ ev->triple_click = 1;
+ else
+ ev->triple_click = 0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+
+ [NSApp sendEvent:event]; // pass along mouse events, for window manager
+ break;
+ }
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ {
+ Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!ev) return;
+ ev->x = [event locationInWindow].x;
+ ev->y = [event locationInWindow].y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->timestamp = time;
+ ev->buttons = [event buttonNumber] + 1; // Apple indexes buttons from 0
+
+ if ([event clickCount] == 2)
+ ev->double_click = 1;
+ else
+ ev->double_click = 0;
+
+ if ([event clickCount] >= 3)
+ ev->triple_click = 1;
+ else
+ ev->triple_click = 0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+
+ [NSApp sendEvent:event]; // pass along mouse events, for window manager
+ break;
+ }
+ case NSKeyDown:
+ {
+ Ecore_Event_Key *ev;
+ unsigned int i;
+
+ ev = calloc(1, sizeof (Ecore_Event_Key));
+ if (!ev) return;
+ ev->timestamp = time;
+
+ for (i = 0; i < sizeof (keystable) / sizeof (struct _ecore_cocoa_keys_s); ++i)
+ {
+ if (keystable[i].code == tolower([[event charactersIgnoringModifiers] characterAtIndex:0]))
+ {
+ ev->keyname = keystable[i].name;
+ ev->string = keystable[i].compose;
+
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL);
+ return;
+ }
+ }
+
+ break;
+ }
+ case NSKeyUp:
+ {
+ Ecore_Event_Key *ev;
+ unsigned int i;
+
+ ev = calloc(1, sizeof (Ecore_Event_Key));
+ if (!ev) return;
+ ev->timestamp = time;
+
+ for (i = 0; i < sizeof (keystable) / sizeof (struct _ecore_cocoa_keys_s); ++i)
+ {
+ if (keystable[i].code == tolower([[event charactersIgnoringModifiers] characterAtIndex:0]))
+ {
+ ev->keyname = keystable[i].name;
+ ev->string = keystable[i].compose;
+
+ ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
+ return;
+ }
+ }
+
+ break;
+ }
+ case NSFlagsChanged:
+ {
+ int flags = [event modifierFlags];
+
+ Ecore_Event_Key *evDown = NULL;
+ Ecore_Event_Key *evUp = NULL;
+
+ evDown = calloc(1, sizeof (Ecore_Event_Key));
+ if (!evDown) return;
+
+ evUp = calloc(1, sizeof (Ecore_Event_Key));
+ if (!evUp)
+ {
+ free(evDown);
+ return;
+ }
+
+ // Turn special key flags on
+ if (flags & NSShiftKeyMask)
+ evDown->keyname = "Shift_L";
+ else if (flags & NSControlKeyMask)
+ evDown->keyname = "Control_L";
+ else if (flags & NSAlternateKeyMask)
+ evDown->keyname = "Alt_L";
+ else if (flags & NSCommandKeyMask)
+ evDown->keyname = "Super_L";
+ else if (flags & NSAlphaShiftKeyMask)
+ evDown->keyname = "Caps_Lock";
+
+ if (evDown->keyname)
+ {
+ evDown->timestamp = time;
+ evDown->string = "";
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, evDown, NULL, NULL);
+ old_flags = flags;
+ break;
+ }
+
+ int changed_flags = flags ^ old_flags;
+
+ // Turn special key flags off
+ if (changed_flags & NSShiftKeyMask)
+ evUp->keyname = "Shift_L";
+ else if (changed_flags & NSControlKeyMask)
+ evUp->keyname = "Control_L";
+ else if (changed_flags & NSAlternateKeyMask)
+ evUp->keyname = "Alt_L";
+ else if (changed_flags & NSCommandKeyMask)
+ evUp->keyname = "Super_L";
+ else if (changed_flags & NSAlphaShiftKeyMask)
+ evUp->keyname = "Caps_Lock";
+
+ if (evUp->keyname)
+ {
+ evUp->timestamp = time;
+ evUp->string = "";
+ ecore_event_add(ECORE_EVENT_KEY_UP, evUp, NULL, NULL);
+ old_flags = flags;
+ break;
+ }
+
+ break;
+ }
+ case NSAppKitDefined:
+ {
+ if ([event subtype] == NSApplicationActivatedEventType)
+ ecore_event_add(ECORE_COCOA_EVENT_GOT_FOCUS, NULL, NULL, NULL);
+ else if ([event subtype] == NSApplicationDeactivatedEventType)
+ ecore_event_add(ECORE_COCOA_EVENT_LOST_FOCUS, NULL, NULL, NULL);
+ [NSApp sendEvent:event]; // pass along AppKit events, for window manager
+ break;
+ }
+ case NSScrollWheel:
+ {
+ break;
+ }
+ default:
+ {
+ [NSApp sendEvent:event];
+ break;
+ }
+ }
+
+ [event release];
+}
diff --git a/src/lib/ecore_cocoa/ecore_cocoa_private.h b/src/lib/ecore_cocoa/ecore_cocoa_private.h
new file mode 100644
index 0000000000..0b4cf3178e
--- /dev/null
+++ b/src/lib/ecore_cocoa/ecore_cocoa_private.h
@@ -0,0 +1,11 @@
+#ifndef _ECORE_COCOA_PRIVATE_H
+#define _ECORE_COCOA_PRIVATE_H
+
+struct _Ecore_Cocoa_Window
+{
+ NSWindow *window;
+ unsigned int borderless : 1;
+};
+
+
+#endif
diff --git a/src/lib/ecore_cocoa/ecore_cocoa_window.m b/src/lib/ecore_cocoa/ecore_cocoa_window.m
new file mode 100644
index 0000000000..2091a69b32
--- /dev/null
+++ b/src/lib/ecore_cocoa/ecore_cocoa_window.m
@@ -0,0 +1,163 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Cocoa/Cocoa.h>
+
+#include "Ecore_Cocoa.h"
+#include "ecore_cocoa_private.h"
+
+Ecore_Cocoa_Window *
+ecore_cocoa_window_new(int x,
+ int y,
+ int width,
+ int height)
+{
+ Ecore_Cocoa_Window *w;
+
+ NSWindow *window = [[NSWindow alloc]
+ initWithContentRect:NSMakeRect(x, y, width, height)
+ styleMask:(NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSResizableWindowMask |
+ NSMiniaturizableWindowMask)
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:nil
+ ];
+
+ if (!window)
+ return NULL;
+
+ [window setBackgroundColor:[NSColor whiteColor]];
+
+ w = calloc(1, sizeof(Ecore_Cocoa_Window));
+ w->window = window;
+ w->borderless = 0;
+
+ return w;
+}
+
+void
+ecore_cocoa_window_free(Ecore_Cocoa_Window *window)
+{
+ if (!window)
+ return;
+
+ [window->window release];
+ free(window);
+}
+
+void
+ecore_cocoa_window_move(Ecore_Cocoa_Window *window,
+ int x,
+ int y)
+{
+ NSRect win_frame;
+
+ if (!window)
+ return;
+
+ win_frame = [window->window frame];
+ win_frame.origin.x = x;
+ win_frame.origin.y = y;
+
+ [window->window setFrame:win_frame display:YES];
+}
+
+void
+ecore_cocoa_window_resize(Ecore_Cocoa_Window *window,
+ int width,
+ int height)
+{
+ if (!window)
+ return;
+
+ NSRect win_frame;
+
+ if (!window)
+ return;
+
+ win_frame = [window->window frame];
+ win_frame.size.height = height;
+ win_frame.size.width = width;
+
+ [window->window setFrame:win_frame display:YES];
+}
+
+void
+ecore_cocoa_window_move_resize(Ecore_Cocoa_Window *window,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ if (!window)
+ return;
+
+ NSRect win_frame;
+
+ if (!window)
+ return;
+
+ win_frame = [window->window frame];
+ win_frame.size.height = height;
+ win_frame.size.width = width;
+ win_frame.origin.x = x;
+ win_frame.origin.y = y;
+
+ [window->window setFrame:win_frame display:YES];
+}
+
+void
+ecore_cocoa_window_title_set(Ecore_Cocoa_Window *window, const char *title)
+{
+ if (!window || !title)
+ return;
+
+ [window->window setTitle:[NSString stringWithUTF8String:title]];
+}
+
+void
+ecore_cocoa_window_show(Ecore_Cocoa_Window *window)
+{
+ if (!window || [window->window isVisible])
+ {
+ printf("Window(%p) is not visible\n", window->window);
+ return;
+ }
+
+ [window->window makeKeyAndOrderFront:NSApp];
+}
+
+void
+ecore_cocoa_window_hide(Ecore_Cocoa_Window *window)
+{
+ if (!window || ![window->window isVisible])
+ return;
+
+ [window->window orderOut:NSApp];
+}
+
+void
+ecore_cocoa_window_borderless_set(Ecore_Cocoa_Window *window,
+ int on)
+{
+ if (!window)
+ return;
+
+ if (on)
+ [window->window setContentBorderThickness:0.0
+ forEdje:NSMinXEdge | NSMinYEdge | NSMaxXEdge | NSMaxYEdge];
+}
+
+void
+ecore_cocoa_window_view_set(Ecore_Cocoa_Window *window,
+ void *view)
+{
+ if (!window || !view)
+ return;
+
+ [[window->window contentView] addSubview:view];
+
+}
diff --git a/src/lib/ecore_con/Ecore_Con.h b/src/lib/ecore_con/Ecore_Con.h
new file mode 100644
index 0000000000..0a832fc37a
--- /dev/null
+++ b/src/lib/ecore_con/Ecore_Con.h
@@ -0,0 +1,1948 @@
+#ifndef _ECORE_CON_H
+#define _ECORE_CON_H
+
+#include <time.h>
+#include <libgen.h>
+#ifdef _WIN32
+# include <ws2tcpip.h>
+#else
+# include <netdb.h>
+#endif
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_CON_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif
+# else
+# define EAPI __declspec(dllimport)
+# endif
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+/**
+ * @defgroup Ecore_Con_Group Ecore_Con - Connection functions
+ *
+ * The Ecore Connection Library ( @c Ecore_Con ) provides simple mechanisms
+ * for communications between programs using reliable sockets. It saves
+ * the programmer from having to worry about file descriptors and waiting
+ * for incoming connections.
+ *
+ * There are two main objects in the @c Ecore_Con library: the @c
+ * Ecore_Con_Server and the @c Ecore_Con_Client.
+ *
+ * The @c Ecore_Con_Server represents a server that can be connected to.
+ * It is used regardless of whether the program is acting as a server or
+ * client itself.
+ *
+ * To create a listening server call @c ecore_con_server_add(), optionally using
+ * an ECORE_CON_USE_* encryption type OR'ed with the type for encryption.
+ *
+ * To connect to a server, call @c ecore_con_server_connect(). Data can
+ * then be sent to the server using the @c ecore_con_server_send().
+ *
+ * Functions are described in the following groupings:
+ * @li @ref Ecore_Con_Lib_Group
+ * @li @ref Ecore_Con_Server_Group
+ * @li @ref Ecore_Con_Client_Group
+ * @li @ref Ecore_Con_Url_Group
+ *
+ * Events are described in @ref Ecore_Con_Events_Group.
+ */
+
+
+/**
+ * @defgroup Ecore_Con_Events_Group Ecore Connection Events Functions
+ *
+ * @li ECORE_CON_CLIENT_ADD: Whenever a client connection is made to an
+ * @c Ecore_Con_Server, an event of this type is emitted, allowing the
+ * retrieval of the client's ip with @ref ecore_con_client_ip_get and
+ * associating data with the client using ecore_con_client_data_set.
+ * @li ECORE_CON_EVENT_CLIENT_DEL: Whenever a client connection to an
+ * @c Ecore_Con_Server, an event of this type is emitted. The contents of
+ * the data with this event are variable, but if the client object in the data
+ * is non-null, it must be freed with @ref ecore_con_client_del.
+ * @li ECORE_CON_EVENT_SERVER_ADD: Whenever a server object is created
+ * with @ref ecore_con_server_connect, an event of this type is emitted,
+ * allowing for data to be serialized and sent to the server using
+ * @ref ecore_con_server_send. At this point, the http handshake has
+ * occurred.
+ * @li ECORE_CON_EVENT_SERVER_DEL: Whenever a server object is destroyed,
+ * usually by the server connection being refused or dropped, an event of this
+ * type is emitted. The contents of the data with this event are variable,
+ * but if the server object in the data is non-null, it must be freed
+ * with @ref ecore_con_server_del.
+ * @li ECORE_CON_EVENT_CLIENT_DATA: Whenever a client connects to your server
+ * object and sends data, an event of this type is emitted. The data will contain both
+ * the size and contents of the message sent by the client. It should be noted that
+ * data within this object is transient, so it must be duplicated in order to be
+ * retained. This event will continue to occur until the client has stopped sending its
+ * message, so a good option for storing this data is an Eina_Strbuf. Once the message has
+ * been received in full, the client object must be freed with ecore_con_client_free.
+ * @li ECORE_CON_EVENT_SERVER_DATA: Whenever your server object connects to its destination
+ * and receives data, an event of this type is emitted. The data will contain both
+ * the size and contents of the message sent by the server. It should be noted that
+ * data within this object is transient, so it must be duplicated in order to be
+ * retained. This event will continue to occur until the server has stopped sending its
+ * message, so a good option for storing this data is an Eina_Strbuf. Once the message has
+ * been received in full, the server object must be freed with ecore_con_server_free.
+ *
+ */
+
+/**
+ * @defgroup Ecore_Con_Buffer Ecore Connection Buffering
+ *
+ * As Ecore_Con works on an event driven design, as data arrives, events will
+ * be produced containing the data that arrived. It is up to the user of
+ * Ecore_Con to either parse as they go, append to a file to later parse the
+ * whole file in one go, or append to memory to parse or handle leter.
+ *
+ * To help with this Eina has some handy API's. The Eina_Binbuf and
+ * Eina_Strbuf APIs, abstract dynamic buffer management and make it trivial
+ * to handle buffers at runtime, without having to manage them. Eina_Binbuf
+ * makes it possible to create, expand, reset and slice a blob of memory -
+ * all via API. No system calls, no pointer manipulations and no size
+ * calculation.
+ *
+ * Additional functions include adding content at specified byte positions in
+ * the buffer, escaping the inputs, find and replace strings. This provides
+ * extreme flexibility to play around, with a dynamic blob of memory.
+ *
+ * It is good to free it (using eina_binbuf_free()) after using it.
+ *
+ * Eina_Binbuf compliments Ecore_Con use cases, where dynamic sizes of data
+ * arrive from the network (think http download in chunks). Using
+ * Eina_Binbuf provides enough flexibility to handle data as it arrives and
+ * to defer its processing until desired, without having to think about
+ * where to store the temporary data and how to manage its size.
+ *
+ * An example of how to use these with Ecore_Con follows.
+ *
+ * @code
+ * #include <Eina.h>
+ * #include <Ecore.h>
+ * #include <Ecore_Con.h>
+ *
+ * static Eina_Bool
+ * data_callback(void *data, int type, void *event)
+ * {
+ * Ecore_Con_Event_Url_Data *url_data = event;
+ * if ( url_data->size > 0)
+ * {
+ * // append data as it arrives - don't worry where or how it gets stored.
+ * // Also don't worry about size, expanding, reallocing etc.
+ * // just keep appending - size is automatically handled.
+ *
+ * eina_binbuf_append_length(data, url_data->data, url_data->size);
+ *
+ * fprintf(stderr, "Appended %d \n", url_data->size);
+ * }
+ * return EINA_TRUE;
+ * }
+ *
+ *
+ *
+ * static Eina_Bool
+ * completion_callback(void *data, int type, void *event)
+ * {
+ * Ecore_Con_Event_Url_Complete *url_complete = event;
+ * printf("download completed with status code: %d\n", url_complete->status);
+ *
+ * // get the data back from Eina_Binbuf
+ * char *ptr = eina_binbuf_string_get(data);
+ * size_t size = eina_binbuf_length_get(data);
+ *
+ * // process data as required (write to file)
+ * fprintf(stderr, "Size of data = %d bytes\n", size);
+ * int fd = open("./elm.png", O_CREAT);
+ * write(fd, ptr, size);
+ * close(fd);
+ *
+ * // free it when done.
+ * eina_binbuf_free(data);
+ *
+ * ecore_main_loop_quit();
+ *
+ * return EINA_TRUE;
+ * }
+ *
+ *
+ * int
+ * main(int argc, char **argv)
+ * {
+ *
+ * const char *url = "http://www.enlightenment.org/p/index/d/logo.png";
+ *
+ * ecore_init();
+ * ecore_con_init();
+ * ecore_con_url_init();
+ *
+ *
+ * // This is single additional line to manage dynamic network data.
+ * Eina_Binbuf *data = eina_binbuf_new();
+ * Ecore_Con_Url *url_con = ecore_con_url_new(url);
+ *
+ * ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE,
+ * completion_callback,
+ * data);
+ * ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA,
+ * data_callback,
+ * data);
+ * ecore_con_url_get(url_con);
+ *
+ * ecore_main_loop_begin();
+ * return 0;
+ * }
+ * @endcode
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define ECORE_CON_USE_SSL ECORE_CON_USE_SSL2
+#define ECORE_CON_REMOTE_SYSTEM ECORE_CON_REMOTE_TCP
+
+
+/**
+ * @typedef Ecore_Con_Server
+ * A connection handle to a server
+ * @ingroup Ecore_Con_Server_Group
+ */
+typedef struct _Ecore_Con_Server Ecore_Con_Server;
+
+/**
+ * @typedef Ecore_Con_Client
+ * A connection handle to a client
+ * @ingroup Ecore_Con_Client_Group
+ */
+typedef struct _Ecore_Con_Client Ecore_Con_Client;
+
+/**
+ * @typedef Ecore_Con_Socks
+ * An object representing a SOCKS proxy
+ * @ingroup Ecore_Con_Socks_Group
+ * @since 1.2
+ */
+typedef struct Ecore_Con_Socks Ecore_Con_Socks;
+
+/**
+ * @typedef Ecore_Con_Url
+ * A handle to an http upload/download object
+ * @ingroup Ecore_Con_Url_Group
+ */
+typedef struct _Ecore_Con_Url Ecore_Con_Url;
+
+
+/**
+ * @addtogroup Ecore_Con_Events_Group
+ * @{
+ */
+
+/**
+ * @typedef Ecore_Con_Event_Client_Add
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Client_Add Ecore_Con_Event_Client_Add;
+
+/**
+ * @typedef Ecore_Con_Event_Client_Upgrade
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Client_Upgrade Ecore_Con_Event_Client_Upgrade;
+
+/**
+ * @typedef Ecore_Con_Event_Client_Del
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Client_Del Ecore_Con_Event_Client_Del;
+
+/**
+ * @typedef Ecore_Con_Event_Client_Error
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Client_Error Ecore_Con_Event_Client_Error;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Add
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Server_Add Ecore_Con_Event_Server_Add;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Upgrade
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Server_Upgrade Ecore_Con_Event_Server_Upgrade;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Del
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Server_Del Ecore_Con_Event_Server_Del;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Error
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Server_Error Ecore_Con_Event_Server_Error;
+
+/**
+ * @typedef Ecore_Con_Event_Client_Data
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Client_Data Ecore_Con_Event_Client_Data;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Data
+ * Used as the @p data param for the corresponding event
+ */
+typedef struct _Ecore_Con_Event_Server_Data Ecore_Con_Event_Server_Data;
+
+/**
+ * @typedef Ecore_Con_Event_Client_Write
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Client_Write Ecore_Con_Event_Client_Write;
+
+/**
+ * @typedef Ecore_Con_Event_Server_Write
+ * Used as the @p data param for the corresponding event
+ * @since 1.1
+ */
+typedef struct _Ecore_Con_Event_Server_Write Ecore_Con_Event_Server_Write;
+
+/**
+ * @typedef Ecore_Con_Event_Proxy_Bind
+ * Used as the @p data param for the corresponding event
+ * @since 1.2
+ */
+typedef struct _Ecore_Con_Event_Proxy_Bind Ecore_Con_Event_Proxy_Bind;
+
+/**
+ * @typedef Ecore_Con_Event_Url_Data
+ * Used as the @p data param for the corresponding event
+ * @ingroup Ecore_Con_Url_Group
+ */
+typedef struct _Ecore_Con_Event_Url_Data Ecore_Con_Event_Url_Data;
+
+/**
+ * @typedef Ecore_Con_Event_Url_Complete
+ * Used as the @p data param for the corresponding event
+ * @ingroup Ecore_Con_Url_Group
+ */
+typedef struct _Ecore_Con_Event_Url_Complete Ecore_Con_Event_Url_Complete;
+
+/**
+ * @typedef Ecore_Con_Event_Url_Progress
+ * Used as the @p data param for the corresponding event
+ * @ingroup Ecore_Con_Url_Group
+ */
+typedef struct _Ecore_Con_Event_Url_Progress Ecore_Con_Event_Url_Progress;
+
+/**
+ * @struct _Ecore_Con_Event_Client_Add
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_ADD event
+ */
+struct _Ecore_Con_Event_Client_Add
+{
+ Ecore_Con_Client *client; /** the client that connected */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Client_Upgrade
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_UPGRADE event
+ * @since 1.1
+ */
+struct _Ecore_Con_Event_Client_Upgrade
+{
+ Ecore_Con_Client *client; /** the client that completed handshake */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Client_Del
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_DEL event
+ */
+struct _Ecore_Con_Event_Client_Del
+{
+ Ecore_Con_Client *client; /** the client that was lost */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Client_Error
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_ERROR event
+ */
+struct _Ecore_Con_Event_Client_Error
+{
+ Ecore_Con_Client *client; /** the client for which an error occurred */
+ char *error; /**< the error string describing what happened */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Add
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_ADD event
+ */
+struct _Ecore_Con_Event_Server_Add
+{
+ Ecore_Con_Server *server; /** the server that was connected to */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Upgrade
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_UPGRADE event
+ * @since 1.1
+ */
+struct _Ecore_Con_Event_Server_Upgrade
+{
+ Ecore_Con_Server *server; /** the server that was connected to */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Del
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_DEL event
+ */
+struct _Ecore_Con_Event_Server_Del
+{
+ Ecore_Con_Server *server; /** the client that was lost */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Error
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_ERROR event
+ */
+struct _Ecore_Con_Event_Server_Error
+{
+ Ecore_Con_Server *server; /** the server for which an error occurred */
+ char *error; /**< the error string describing what happened */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Client_Data
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_DATA event
+ */
+struct _Ecore_Con_Event_Client_Data
+{
+ Ecore_Con_Client *client; /**< the client that connected */
+ void *data; /**< the data that the client sent */
+ int size; /**< the length of the data sent */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Data
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_DATA event
+ */
+struct _Ecore_Con_Event_Server_Data
+{
+ Ecore_Con_Server *server; /**< the server that was connected to */
+ void *data; /**< the data that the server sent */
+ int size; /**< the length of the data sent */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Client_Write
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_WRITE event
+ */
+struct _Ecore_Con_Event_Client_Write
+{
+ Ecore_Con_Client *client; /**< the client that connected */
+ int size; /**< the length of the data sent */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Server_Write
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_WRITE event
+ */
+struct _Ecore_Con_Event_Server_Write
+{
+ Ecore_Con_Server *server; /**< the server that was connected to */
+ int size; /**< the length of the data sent */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Proxy_Bind
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_PROXY_BIND event
+ * @ingroup Ecore_Con_Socks_Group
+ * @since 1.2
+ */
+struct _Ecore_Con_Event_Proxy_Bind
+{
+ Ecore_Con_Server *server; /**< the server object connected to the proxy */
+ const char *ip; /**< the proxy-bound ip address */
+ int port; /**< the proxy-bound port */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Url_Data
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_DATA event
+ * @ingroup Ecore_Con_Url_Group
+ */
+struct _Ecore_Con_Event_Url_Data
+{
+ Ecore_Con_Url *url_con; /**< a pointer to the connection object */
+ int size; /**< the size of the current received data (in bytes) */
+ unsigned char data[1]; /**< the data received on this event */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Url_Complete
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_COMPLETE event
+ * @ingroup Ecore_Con_Url_Group
+ */
+struct _Ecore_Con_Event_Url_Complete
+{
+ Ecore_Con_Url *url_con; /**< a pointer to the connection object */
+ int status; /**< HTTP status code of the operation (200, 404, 401, etc.) */
+};
+
+/**
+ * @struct _Ecore_Con_Event_Url_Progress
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_PROGRESS event
+ * @ingroup Ecore_Con_Url_Group
+ */
+struct _Ecore_Con_Event_Url_Progress
+{
+ Ecore_Con_Url *url_con; /**< a pointer to the connection object */
+ struct
+ {
+ double total; /**< total size of the downloading data (in bytes) */
+ double now; /**< current size of the downloading data (in bytes) */
+ } down; /**< download info */
+ struct
+ {
+ double total; /**< total size of the uploading data (in bytes) */
+ double now; /**< current size of the uploading data (in bytes) */
+ } up; /**< upload info */
+};
+
+/** A client has connected to the server */
+EAPI extern int ECORE_CON_EVENT_CLIENT_ADD;
+/** A client has disconnected from the server */
+EAPI extern int ECORE_CON_EVENT_CLIENT_DEL;
+/** A client experienced an error
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_CLIENT_ERROR;
+/** A client connection has been upgraded to SSL
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_CLIENT_UPGRADE;
+/** A server was created */
+EAPI extern int ECORE_CON_EVENT_SERVER_ADD;
+/** A server connection was lost */
+EAPI extern int ECORE_CON_EVENT_SERVER_DEL;
+/** A server experienced an error
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_SERVER_ERROR;
+/** A server connection has been upgraded to SSL
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_SERVER_UPGRADE;
+/** A server connection has sent data to its client
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_CLIENT_WRITE;
+/** A server connection object has sent data
+ * @since 1.1
+ */
+EAPI extern int ECORE_CON_EVENT_SERVER_WRITE;
+/** A client connected to the server has sent data */
+EAPI extern int ECORE_CON_EVENT_CLIENT_DATA;
+/** A server connection object has data */
+EAPI extern int ECORE_CON_EVENT_SERVER_DATA;
+/** A server connection has successfully negotiated an ip:port binding
+ * @since 1.2
+ */
+EAPI extern int ECORE_CON_EVENT_PROXY_BIND;
+/** A URL object has data */
+EAPI extern int ECORE_CON_EVENT_URL_DATA;
+/** A URL object has completed its transfer to and from the server and can be reused */
+EAPI extern int ECORE_CON_EVENT_URL_COMPLETE;
+/** A URL object has made progress in its transfer */
+EAPI extern int ECORE_CON_EVENT_URL_PROGRESS;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Con_Lib_Group Ecore Connection Library Functions
+ *
+ * Utility functions that set up and shut down the Ecore Connection
+ * library.
+ *
+ * There's also ecore_con_lookup() that can be used to make simple asynchronous
+ * DNS lookups.
+ *
+ * A simple example of how to use these functions:
+ * @li @ref ecore_con_lookup_example_c
+ *
+ * @{
+ */
+
+/**
+ * @typedef Ecore_Con_Dns_Cb
+ * A callback type for use with @ref ecore_con_lookup.
+ */
+typedef void (*Ecore_Con_Dns_Cb)(const char *canonname,
+ const char *ip,
+ struct sockaddr *addr,
+ int addrlen,
+ void *data);
+
+/**
+ * @typedef Ecore_Con_Type
+ * @enum _Ecore_Con_Type
+ * Types for an ecore_con client/server object. A correct way to set this type is
+ * with an ECORE_CON_$TYPE, optionally OR'ed with an ECORE_CON_$USE if encryption is desired,
+ * and LOAD_CERT if the previously loaded certificate should be used.
+ * @code
+ * ECORE_CON_REMOTE_TCP | ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT
+ * @endcode
+ * @ingroup Ecore_Con_Server_Group
+ */
+typedef enum _Ecore_Con_Type
+{
+ /** Socket in ~/.ecore */
+ ECORE_CON_LOCAL_USER = 0,
+ /** Socket in /tmp */
+ ECORE_CON_LOCAL_SYSTEM = 1,
+ /** Abstract socket */
+ ECORE_CON_LOCAL_ABSTRACT = 2,
+ /** Remote server using TCP */
+ ECORE_CON_REMOTE_TCP = 3,
+ /** Remote multicast server */
+ ECORE_CON_REMOTE_MCAST = 4,
+ /** Remote server using UDP */
+ ECORE_CON_REMOTE_UDP = 5,
+ /** Remote broadcast using UDP */
+ ECORE_CON_REMOTE_BROADCAST = 6,
+ /** Remote connection sending packets immediately */
+ ECORE_CON_REMOTE_NODELAY = 7,
+ /** Remote connection sending data in large chunks
+ * @note Only available on Linux
+ * @since 1.2
+ */
+ ECORE_CON_REMOTE_CORK = 8,
+ /** Use SSL2: UNSUPPORTED. **/
+ ECORE_CON_USE_SSL2 = (1 << 4),
+ /** Use SSL3 */
+ ECORE_CON_USE_SSL3 = (1 << 5),
+ /** Use TLS */
+ ECORE_CON_USE_TLS = (1 << 6),
+ /** Use both TLS and SSL3 */
+ ECORE_CON_USE_MIXED = ECORE_CON_USE_SSL3 | ECORE_CON_USE_TLS,
+ /** Attempt to use the loaded certificate */
+ ECORE_CON_LOAD_CERT = (1 << 7),
+ /** Disable all types of proxy on the server
+ * @note Only functional for clients
+ * @since 1.2
+ */
+ ECORE_CON_NO_PROXY = (1 << 8)
+} Ecore_Con_Type;
+
+/**
+ * Initialises the Ecore_Con library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ *
+ * @note This function already calls ecore_init() internally, so you don't need
+ * to call it explicitly.
+ */
+EAPI int ecore_con_init(void);
+
+/**
+ * Shuts down the Ecore_Con library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ * @note This function already calls ecore_shutdown() internally, so you don't
+ * need to call it explicitly unless you called ecore_init() explicitly too.
+ */
+EAPI int ecore_con_shutdown(void);
+
+/**
+ * Do an asynchronous DNS lookup.
+ *
+ * @param name IP address or server name to translate.
+ * @param done_cb Callback to notify when done.
+ * @param data User data to be given to done_cb.
+ * @return @c EINA_TRUE if the request did not fail to be set up, @c EINA_FALSE
+ * if it failed.
+ *
+ * This function performs a DNS lookup on the hostname specified by @p name,
+ * then calls @p done_cb with the result and the @p data given as parameter.
+ * The result will be given to the @p done_cb as follows:
+ * @li @c canonname - the canonical name of the address
+ * @li @c ip - the resolved ip address
+ * @li @c addr - a pointer to the socket address
+ * @li @c addrlen - the length of the socket address, in bytes
+ * @li @c data - the data pointer given as parameter to ecore_con_lookup()
+ */
+EAPI Eina_Bool ecore_con_lookup(const char *name,
+ Ecore_Con_Dns_Cb done_cb,
+ const void *data);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Con_SSL_Group Ecore Connection SSL Functions
+ *
+ * @{
+ */
+EAPI int ecore_con_ssl_available_get(void);
+EAPI Eina_Bool ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, const char *cert);
+EAPI Eina_Bool ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, const char *key_file);
+EAPI Eina_Bool ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const char *crl_file);
+EAPI Eina_Bool ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *ca_file);
+EAPI void ecore_con_ssl_server_verify(Ecore_Con_Server *svr);
+EAPI void ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr);
+EAPI void ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name);
+EAPI const char *ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr);
+EAPI Eina_Bool ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type);
+EAPI Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type);
+
+/**
+ * @}
+ */
+
+EAPI Ecore_Con_Socks *ecore_con_socks4_remote_add(const char *ip, int port, const char *username);
+EAPI Eina_Bool ecore_con_socks4_remote_exists(const char *ip, int port, const char *username);
+EAPI void ecore_con_socks4_remote_del(const char *ip, int port, const char *username);
+EAPI Ecore_Con_Socks *ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password);
+EAPI Eina_Bool ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password);
+EAPI void ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password);
+EAPI void ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable);
+EAPI Eina_Bool ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind);
+EAPI Eina_Bool ecore_con_socks_bind_get(Ecore_Con_Socks *ecs);
+EAPI unsigned int ecore_con_socks_version_get(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_remote_del(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_apply_once(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_apply_always(Ecore_Con_Socks *ecs);
+
+/**
+ * @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions
+ *
+ * This group of functions is applied to an @ref Ecore_Con_Server object. It
+ * doesn't mean that they should be used in the server application, but on the
+ * server object. In fact, most of them should be used in the client
+ * application, when retrieving information or sending data.
+ *
+ * Setting up a server is very simple: you just need to start it with
+ * ecore_con_server_add() and setup some callbacks to the events
+ * @ref ECORE_CON_EVENT_CLIENT_ADD, @ref ECORE_CON_EVENT_CLIENT_DEL and
+ * @ref ECORE_CON_EVENT_CLIENT_DATA, that will be called when a client is
+ * communicating with the server:
+ *
+ * @code
+ * if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL)))
+ * exit(1);
+ *
+ * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, _add_cb, NULL);
+ * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, _del_cb, NULL);
+ * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, _data_cb, NULL);
+ *
+ * ecore_main_loop_begin();
+ * @endcode
+ *
+ * The function ecore_con_server_connect() can be used to write a client that
+ * connects to a server. The resulting code will be very similar to the server
+ * code:
+ *
+ * @code
+ * if (!(svr = ecore_con_server_connect(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL)))
+ * exit(1);
+ *
+ * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, _add_cb, NULL);
+ * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, _del_cb, NULL);
+ * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, _data_cb, NULL);
+ *
+ * ecore_main_loop_begin();
+ * @endcode
+ *
+ * After these two pieces of code are executed, respectively, in the server and
+ * client code, the server will be up and running and the client will try to
+ * connect to it. The connection, with its subsequent messages being sent from
+ * server to client and client to server, can be represented in the following
+ * sequence diagram:
+ *
+ * @htmlonly
+ * <img src="ecore_con-client-server.png" style="max-width: 400px"/>
+ * <a href="ecore_con-client-server.png">Full size</a>
+ * @endhtmlonly
+ *
+ * @image rtf ecore_con-client-server.png
+ * @image latex ecore_con-client-server.eps width=\textwidth
+ *
+ * Please notice the important difference between these two codes: the first is
+ * used for writing a @b server, while the second should be used for writing a
+ * @b client.
+ *
+ * A reference for the @c client functions can be found at @ref
+ * Ecore_Con_Client_Group.
+ *
+ * Examples of usage for this API can be found here:
+ * @li @ref ecore_con_server_simple_example_c
+ * @li @ref ecore_con_client_simple_example_c
+ *
+ * @{
+ */
+
+/**
+ * Creates a server to listen for connections.
+ *
+ * @param type The connection type.
+ * @param name Name to associate with the socket. It is used when
+ * generating the socket name of a Unix socket, or for
+ * determining what host to listen on for TCP sockets.
+ * @c NULL will not be accepted.
+ * @param port Number to identify socket. When a Unix socket is used,
+ * it becomes part of the socket name. When a TCP socket
+ * is used, it is used as the TCP port.
+ * @param data Data to associate with the created Ecore_Con_Server
+ * object.
+ * @return A new Ecore_Con_Server.
+ *
+ * The socket on which the server listens depends on the connection
+ * type:
+ * @li If @a type is @c ECORE_CON_LOCAL_USER, the server will listen on
+ * the Unix socket "~/.ecore/[name]/[port]".
+ * @li If @a type is @c ECORE_CON_LOCAL_SYSTEM, the server will listen
+ * on Unix socket "/tmp/.ecore_service|[name]|[port]".
+ * @li If @a type is @c ECORE_CON_REMOTE_TCP, the server will listen
+ * on TCP port @c port.
+ *
+ * More information about the @p type can be found at @ref _Ecore_Con_Type.
+ *
+ * The @p data parameter can be fetched later using ecore_con_server_data_get()
+ * or changed with ecore_con_server_data_set().
+ */
+EAPI Ecore_Con_Server *ecore_con_server_add(Ecore_Con_Type type,
+ const char *name, int port,
+ const void *data);
+
+/**
+ * Creates a connection to the specified server and returns an associated object.
+ *
+ * @param type The connection type.
+ * @param name Name used when determining what socket to connect to.
+ * It is used to generate the socket name when the socket
+ * is a Unix socket. It is used as the hostname when
+ * connecting with a TCP socket.
+ * @param port Number to identify the socket to connect to. Used when
+ * generating the socket name for a Unix socket, or as the
+ * TCP port when connecting to a TCP socket.
+ * @param data Data to associate with the created Ecore_Con_Server
+ * object.
+ * @return A new Ecore_Con_Server.
+ *
+ * The socket to which the connection is made depends on the connection type:
+ * @li If @a type is @c ECORE_CON_LOCAL_USER, the function will
+ * connect to the server at the Unix socket
+ * "~/.ecore/[name]/[port]".
+ * @li If @a type is @c ECORE_CON_LOCAL_SYSTEM, the function will
+ * connect to the server at the Unix socket
+ * "/tmp/.ecore_service|[name]|[port]".
+ * @li If @a type is @c ECORE_CON_REMOTE_TCP, the function will
+ * connect to the server at the TCP port "[name]:[port]".
+ *
+ * More information about the @p type can be found at @ref _Ecore_Con_Type.
+ *
+ * This function won't block. It will either succeed, or fail due to invalid
+ * parameters, failed memory allocation, etc., returning @c NULL on that case.
+ *
+ * However, even if this call returns a valid @ref Ecore_Con_Server, the
+ * connection will only be successfully completed if an event of type
+ * @ref ECORE_CON_EVENT_SERVER_ADD is received. If it fails to complete, an
+ * @ref ECORE_CON_EVENT_SERVER_DEL will be received.
+ *
+ * The @p data parameter can be fetched later using ecore_con_server_data_get()
+ * or changed with ecore_con_server_data_set().
+ */
+EAPI Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type,
+ const char *name, int port,
+ const void *data);
+/**
+ * Closes the connection and frees the given server.
+ *
+ * @param svr The given server.
+ * @return Data associated with the server when it was created.
+ *
+ * All the clients connected to this server will be disconnected.
+ *
+ * @see ecore_con_server_add, ecore_con_server_connect
+ */
+EAPI void * ecore_con_server_del(Ecore_Con_Server *svr);
+
+/**
+ * Retrieves the data associated with the given server.
+ *
+ * @param svr The given server.
+ * @return The associated data.
+ *
+ * @see ecore_con_server_data_set()
+ */
+EAPI void * ecore_con_server_data_get(Ecore_Con_Server *svr);
+/**
+ * Sets the data associated with the given server.
+ *
+ * @param svr The given server.
+ * @param data The data to associate with @p svr
+ * @return The previously associated data, if any.
+ *
+ * @see ecore_con_server_data_get()
+ */
+EAPI void * ecore_con_server_data_set(Ecore_Con_Server *svr,
+ void *data);
+/**
+ * Retrieves whether the given server is currently connected.
+ *
+ * @param svr The given server.
+ * @return @c EINA_TRUE if the server is connected, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_con_server_connected_get(Ecore_Con_Server *svr);
+/**
+ * Retrieves the current list of clients.
+ *
+ * @param svr The given server.
+ * @return The list of clients on this server.
+ *
+ * Each node in the returned list points to an @ref Ecore_Con_Client. This list
+ * cannot be modified or freed. It can also change if new clients are connected
+ * or disconnected, and will become invalid when the server is deleted/freed.
+ */
+EAPI const Eina_List * ecore_con_server_clients_get(Ecore_Con_Server *svr);
+
+/**
+ * Retrieves the name of server.
+ *
+ * @param svr The given server.
+ * @return The name of the server.
+ *
+ * The name returned is the name used to connect on this server.
+ */
+EAPI const char * ecore_con_server_name_get(Ecore_Con_Server *svr);
+
+/**
+ * Retrieves the server port in use.
+ *
+ * @param svr The given server.
+ * @return The server port in use.
+ *
+ * The port where the server is listening for connections.
+ */
+EAPI int ecore_con_server_port_get(Ecore_Con_Server *svr);
+/**
+ * @brief Check how long a server has been connected
+ *
+ * @param svr The server to check
+ * @return The total time, in seconds, that the server has been
+ * connected/running
+ *
+ * This function is used to find out the time that has been elapsed since
+ * ecore_con_server_add() succeeded.
+ */
+EAPI double ecore_con_server_uptime_get(Ecore_Con_Server *svr);
+/**
+ * Sends the given data to the given server.
+ *
+ * @param svr The given server.
+ * @param data The given data.
+ * @param size Length of the data, in bytes, to send.
+ * @return The number of bytes sent. @c 0 will be returned if there is an
+ * error.
+ *
+ * This function will send the given data to the server as soon as the program
+ * is back to the main loop. Thus, this function returns immediately
+ * (non-blocking). If the data needs to be sent @b now, call
+ * ecore_con_server_flush() after this one.
+ *
+ * @see ecore_con_client_send()
+ * @see ecore_con_server_flush()
+ */
+EAPI int ecore_con_server_send(Ecore_Con_Server *svr,
+ const void *data,
+ int size);
+/**
+ * Sets a limit on the number of clients that can be handled concurrently
+ * by the given server, and a policy on what to do if excess clients try to
+ * connect.
+ *
+ * @param svr The given server.
+ * @param client_limit The maximum number of clients to handle
+ * concurrently. -1 means unlimited (default). 0
+ * effectively disables the server.
+ * @param reject_excess_clients Set to 1 to automatically disconnect
+ * excess clients as soon as they connect if you are
+ * already handling client_limit clients. Set to 0
+ * (default) to just hold off on the "accept()"
+ * system call until the number of active clients
+ * drops. This causes the kernel to queue up to 4096
+ * connections (or your kernel's limit, whichever is
+ * lower).
+ *
+ * Beware that if you set this once ecore is already running, you may
+ * already have pending CLIENT_ADD events in your event queue. Those
+ * clients have already connected and will not be affected by this call.
+ * Only clients subsequently trying to connect will be affected.
+ */
+EAPI void ecore_con_server_client_limit_set(Ecore_Con_Server *svr,
+ int client_limit,
+ char reject_excess_clients);
+/**
+ * Gets the IP address of a server that has been connected to.
+ *
+ * @param svr The given server.
+ * @return A pointer to an internal string that contains the IP address of
+ * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation.
+ * This string should not be modified or trusted to stay valid after
+ * deletion for the @p svr object. If no IP is known @c NULL is
+ * returned.
+ */
+EAPI const char * ecore_con_server_ip_get(Ecore_Con_Server *svr);
+/**
+ * Flushes all pending data to the given server.
+ *
+ * @param svr The given server.
+ *
+ * This function will block until all data is sent to the server.
+ *
+ * @see ecore_con_server_send()
+ * @see ecore_con_client_flush()
+ */
+EAPI void ecore_con_server_flush(Ecore_Con_Server *svr);
+/**
+ * Set the default time after which an inactive client will be disconnected
+ *
+ * @param svr The server object
+ * @param timeout The timeout, in seconds, to disconnect after
+ *
+ * This function is used by the server to set the default idle timeout on
+ * clients. If the any of the clients becomes idle for a time higher than this
+ * value, it will be disconnected. A value of < 1 disables the idle timeout.
+ *
+ * This timeout is not affected by the one set by
+ * ecore_con_client_timeout_set(). A client will be disconnected whenever the
+ * client or the server timeout is reached. That means, the lower timeout value
+ * will be used for that client if ecore_con_client_timeout_set() is used on it.
+ *
+ * @see ecore_con_server_timeout_get()
+ * @see ecore_con_client_timeout_set()
+ */
+EAPI void ecore_con_server_timeout_set(Ecore_Con_Server *svr, double timeout);
+/**
+ * Get the default time after which an inactive client will be disconnected
+ *
+ * @param svr The server object
+ * @return The timeout, in seconds, to disconnect after
+ *
+ * This function is used to get the idle timeout for clients. A value of < 1
+ * means the idle timeout is disabled.
+ *
+ * @see ecore_con_server_timeout_set()
+ * @see ecore_con_client_timeout_get()
+ */
+EAPI double ecore_con_server_timeout_get(Ecore_Con_Server *svr);
+
+/**
+ * Get the fd that the server is connected to
+ *
+ * @param svr The server object
+ * @return The fd, or -1 on failure
+ *
+ * This function returns the fd which is used by the underlying server connection.
+ * It should not be tampered with unless you REALLY know what you are doing.
+ * @note This function is only valid for servers created with ecore_con_server_connect()
+ * @warning Seriously. Don't use this unless you know what you are doing.
+ * @since 1.1
+ */
+EAPI int ecore_con_server_fd_get(Ecore_Con_Server *svr);
+
+/**
+ * Get the fd that the client is connected to
+ *
+ * @param cl The client object
+ * @return The fd, or -1 on failure
+ *
+ * This function returns the fd which is used by the underlying client connection.
+ * It should not be tampered with unless you REALLY know what you are doing.
+ * @since 1.1
+ */
+EAPI int ecore_con_client_fd_get(Ecore_Con_Client *cl);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Con_Client_Group Ecore Connection Client Functions
+ *
+ * Functions to communicate with and/or set options on a client.
+ *
+ * This set of functions, as explained in @ref Ecore_Con_Server_Group, is used
+ * to send data to a client, or to set options and get information about this
+ * client. Most of them should be used on the server, applied on the client
+ * object.
+ *
+ * If you need to implement a client, the way to connect to a server is
+ * described in @ref Ecore_Con_Server_Group.
+ *
+ * An example of usage of these functions can be found at:
+ * @li @ref ecore_con_client_simple_example_c
+ *
+ * @{
+ */
+
+/**
+ * Sends the given data to the given client.
+ *
+ * @param cl The given client.
+ * @param data The given data.
+ * @param size Length of the data, in bytes, to send.
+ * @return The number of bytes sent. @c 0 will be returned if there is an
+ * error.
+ *
+ * This function will send the given data to the client as soon as the program
+ * is back to the main loop. Thus, this function returns immediately
+ * (non-blocking). If the data needs to be sent @b now, call
+ * ecore_con_client_flush() after this one.
+ *
+ * @see ecore_con_server_send()
+ * @see ecore_con_client_flush()
+ */
+EAPI int ecore_con_client_send(Ecore_Con_Client *cl,
+ const void *data,
+ int size);
+/**
+ * Retrieves the server representing the socket the client has
+ * connected to.
+ *
+ * @param cl The given client.
+ * @return The server that the client connected to.
+ */
+EAPI Ecore_Con_Server *ecore_con_client_server_get(Ecore_Con_Client *cl);
+/**
+ * Closes the connection and frees memory allocated to the given client.
+ *
+ * @param cl The given client.
+ * @return Data associated with the client.
+ */
+EAPI void * ecore_con_client_del(Ecore_Con_Client *cl);
+/**
+ * Sets the data associated with the given client to @p data.
+ *
+ * @param cl The given client.
+ * @param data What to set the data to.
+ */
+EAPI void ecore_con_client_data_set(Ecore_Con_Client *cl,
+ const void *data);
+/**
+ * Retrieves the data associated with the given client.
+ *
+ * @param cl The given client.
+ * @return The data associated with @p cl.
+ */
+EAPI void * ecore_con_client_data_get(Ecore_Con_Client *cl);
+
+/**
+ * Gets the IP address of a client that has connected.
+ *
+ * @param cl The given client.
+ * @return A pointer to an internal string that contains the IP address of
+ * the connected client in the form "XXX.YYY.ZZZ.AAA" IP notation.
+ *
+ * The returned string should not be modified, freed or trusted to stay valid
+ * after deletion for the @p cl object. If no IP is known @c NULL is returned.
+ */
+EAPI const char * ecore_con_client_ip_get(Ecore_Con_Client *cl);
+/**
+ * Flushes all pending data to the given client.
+ *
+ * @param cl The given client.
+ *
+ * This function will block until all data is sent to the server.
+ *
+ * @see ecore_con_client_send()
+ * @see ecore_con_server_flush()
+ */
+EAPI void ecore_con_client_flush(Ecore_Con_Client *cl);
+/**
+ * @brief Check how long a client has been connected
+ *
+ * @param cl The client to check
+ * @return The total time, in seconds, that the client has been connected to
+ * the server
+ *
+ * This function is used to find out how long a client has been connected for.
+ */
+EAPI double ecore_con_client_uptime_get(Ecore_Con_Client *cl);
+/**
+ * Get the default time after which the client will be disconnected when
+ * inactive
+ *
+ * @param cl The client object
+ * @return The timeout, in seconds, to disconnect after
+ *
+ * This function is used to get the idle timeout for a client. A value of < 1
+ * means the idle timeout is disabled.
+ *
+ * @see ecore_con_client_timeout_set()
+ */
+EAPI double ecore_con_client_timeout_get(Ecore_Con_Client *cl);
+/**
+ * Set the time after which the client will be disconnected when inactive
+ *
+ * @param cl The client object
+ * @param timeout The timeout, in seconds, to disconnect after
+ *
+ * This function is used by the server to set the idle timeout on a specific
+ * client. If the client becomes idle for a time higher than this value, it will
+ * be disconnected. A value of < 1 disables the idle timeout.
+ *
+ * This timeout is not affected by the one set by
+ * ecore_con_server_timeout_set(). A client will be disconnected whenever the
+ * client or the server timeout is reached. That means, the lower timeout value
+ * will be used for that client if ecore_con_server_timeout_set() is used on the
+ * server.
+ *
+ * @see ecore_con_client_timeout_get()
+ * @see ecore_con_server_timeout_set()
+ */
+EAPI void ecore_con_client_timeout_set(Ecore_Con_Client *cl, double timeout);
+/**
+ * Returns whether the client is still connected
+ *
+ * @param cl The given client.
+ * @return @c EINA_TRUE if connected, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_con_client_connected_get(Ecore_Con_Client *cl);
+/**
+ * @brief Return the port that the client has connected to
+ *
+ * @param cl The client
+ * @return The port that @p cl has connected to, or -1 on error
+ * Use this function to return the port on which a given client has connected.
+ */
+EAPI int ecore_con_client_port_get(Ecore_Con_Client *cl);
+
+
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Con_Url_Group Ecore URL Connection Functions
+ *
+ * Utility functions that set up, use and shut down the Ecore URL
+ * Connection library.
+ *
+ * These functions are a shortcut to make it easy to perform http requests
+ * (POST, GET, etc).
+ *
+ * Brief usage:
+ * 1. Create an Ecore_Con_Url object with ecore_con_url_new(url);
+ * 2. Register to receive the #ECORE_CON_EVENT_URL_COMPLETE event
+ * (and optionally the #ECORE_CON_EVENT_URL_DATA and
+ * #ECORE_CON_EVENT_URL_PROGRESS event to receive
+ * the response, e.g. for HTTP/FTP downloads)
+ * 3. Perform the operation with ecore_con_url_get(...);
+ *
+ * Note that it is good to reuse @ref Ecore_Con_Url objects wherever possible,
+ * but bear in mind that each one can only perform one operation at a time. You
+ * need to wait for the #ECORE_CON_EVENT_URL_COMPLETE event before re-using or
+ * destroying the object.
+ *
+ * If it's necessary to change the @ref Ecore_Con_Url object url, use
+ * ecore_con_url_url_set().
+ *
+ * Simple Usage 1 (HTTP GET):
+ * @code
+ * ecore_con_url_url_set(url_con, "http://www.google.com");
+ * ecore_con_url_get(url_con);
+ * @endcode
+ *
+ * Simple usage 2 (HTTP POST):
+ * @code
+ * ecore_con_url_url_set(url_con, "http://www.example.com/post_handler.cgi");
+ * ecore_con_url_post(url_con, data, data_length, "multipart/form-data");
+ * @endcode
+ *
+ * Simple Usage 3 (FTP download):
+ * @code
+ * fd = creat(filename, 0644)
+ * ecore_con_url_url_set(url_con, "ftp://ftp.example.com/pub/myfile");
+ * ecore_con_url_fd_set(url_con, fd);
+ * ecore_con_url_get(url_con);
+ * @endcode
+ *
+ * Simple Usage 4 (FTP upload as ftp://ftp.example.com/file):
+ * @code
+ * ecore_con_url_url_set(url_con, "ftp://ftp.example.com");
+ * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass", NULL);
+ * @endcode
+ *
+ * Simple Usage 5 (FTP upload as ftp://ftp.example.com/dir/file):
+ * @code
+ * ecore_con_url_url_set(url_con, "ftp://ftp.example.com");
+ * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass","dir");
+ * @endcode
+ *
+ * These are complete examples for the API:
+ * @li @ref ecore_con_url_download_example.c "Downloading a file"
+ * @li @ref ecore_con_url_headers_example.c "Setting many options for the connection"
+ *
+ * @{
+ */
+
+/**
+ * @typedef Ecore_Con_Url_Time
+ * @enum _Ecore_Con_Url_Time
+ * The type of condition to use when making an HTTP request dependent on time,
+ * so that headers such as "If-Modified-Since" are used.
+ */
+typedef enum _Ecore_Con_Url_Time
+{
+ /**
+ * Do not place time restrictions on the HTTP requests.
+ */
+ ECORE_CON_URL_TIME_NONE = 0,
+ /**
+ * Add the "If-Modified-Since" HTTP header, so that the request is performed
+ * by the server only if the target has been modified since the time value
+ * passed to it in the request.
+ */
+ ECORE_CON_URL_TIME_IFMODSINCE,
+ /**
+ * Add the "If-Unmodified-Since" HTTP header, so that the request is
+ * performed by the server only if the target has NOT been modified since
+ * the time value passed to it in the request.
+ */
+ ECORE_CON_URL_TIME_IFUNMODSINCE
+} Ecore_Con_Url_Time;
+
+/**
+ * @typedef Ecore_Con_Url_Http_Version
+ * @enum _Ecore_Con_Url_Http_Version
+ * The http version to use
+ * @since 1.2
+ */
+typedef enum _Ecore_Con_Url_Http_Version
+{
+ /**
+ * HTTP version 1.0
+ * @since 1.2
+ */
+ ECORE_CON_URL_HTTP_VERSION_1_0,
+ /**
+ * HTTP version 1.1 (default)
+ * @since 1.2
+ */
+ ECORE_CON_URL_HTTP_VERSION_1_1
+} Ecore_Con_Url_Http_Version;
+
+/**
+ * Change the HTTP version used for the request
+ * @param url_con Connection object through which the request will be sent.
+ * @param version The version to be used
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure to change version.
+ * @since 1.2
+ * @see ecore_con_url_pipeline_get()
+ */
+EAPI Eina_Bool ecore_con_url_http_version_set(Ecore_Con_Url *url_con, Ecore_Con_Url_Http_Version version);
+
+/**
+ * Initialises the Ecore_Con_Url library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ *
+ * @note This function doesn't call ecore_con_init(). You still need to call it
+ * explicitly before calling this one.
+ */
+EAPI int ecore_con_url_init(void);
+
+/**
+ * Shuts down the Ecore_Con_Url library.
+ * @return Number of calls that still uses Ecore_Con_Url
+ *
+ * @note This function doesn't call ecore_con_shutdown(). You still need to call
+ * it explicitly after calling this one.
+ */
+EAPI int ecore_con_url_shutdown(void);
+
+/**
+ * Enable or disable HTTP 1.1 pipelining.
+ * @param enable @c EINA_TRUE will turn it on, @c EINA_FALSE will disable it.
+ *
+ * Pipelining allows to send one request after another one, without having to
+ * wait for the reply of the first request. The respective replies are received
+ * in the order that the requests were sent.
+ *
+ * Enabling this feature will be valid for all requests done using @c
+ * ecore_con_url.
+ *
+ * See http://en.wikipedia.org/wiki/HTTP_pipelining for more info.
+ *
+ * @see ecore_con_url_pipeline_get()
+ */
+EAPI void ecore_con_url_pipeline_set(Eina_Bool enable);
+/**
+ * Is HTTP 1.1 pipelining enable ?
+ * @return @c EINA_TRUE if it is enable.
+ *
+ * @see ecore_con_url_pipeline_set()
+ */
+EAPI Eina_Bool ecore_con_url_pipeline_get(void);
+
+/**
+ * Creates and initializes a new Ecore_Con_Url connection object.
+ *
+ * @param url URL that will receive requests. Can be changed using
+ * ecore_con_url_url_set.
+ *
+ * @return @c NULL on error, a new Ecore_Con_Url on success.
+ *
+ * Creates and initializes a new Ecore_Con_Url connection object that can be
+ * used for sending requests.
+ *
+ * @see ecore_con_url_custom_new()
+ * @see ecore_con_url_url_set()
+ */
+EAPI Ecore_Con_Url * ecore_con_url_new(const char *url);
+/**
+ * Creates a custom connection object.
+ *
+ * @param url URL that will receive requests
+ * @param custom_request Custom request (e.g. GET, POST, HEAD, PUT, etc)
+ *
+ * @return @c NULL on error, a new Ecore_Con_Url on success.
+ *
+ * Creates and initializes a new Ecore_Con_Url for a custom request (e.g. HEAD,
+ * SUBSCRIBE and other obscure HTTP requests). This object should be used like
+ * one created with ecore_con_url_new().
+ *
+ * @see ecore_con_url_new()
+ * @see ecore_con_url_url_set()
+ */
+EAPI Ecore_Con_Url * ecore_con_url_custom_new(const char *url,
+ const char *custom_request);
+/**
+ * Destroys a Ecore_Con_Url connection object.
+ *
+ * @param url_con Connection object to free.
+ *
+ * @see ecore_con_url_new()
+ */
+EAPI void ecore_con_url_free(Ecore_Con_Url *url_con);
+/**
+ * Sets the URL to send the request to.
+ *
+ * @param url_con Connection object through which the request will be sent.
+ * @param url URL that will receive the request
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ */
+EAPI Eina_Bool ecore_con_url_url_set(Ecore_Con_Url *url_con,
+ const char *url);
+/**
+ * Gets the URL to send the request to.
+ *
+ * @param url_con Connection object through which the request will be sent.
+ * @return URL that will receive the request, @c NULL on failure. URL is
+ * stringshared.
+ * @since 1.1
+ */
+EAPI const char *ecore_con_url_url_get(Ecore_Con_Url *url_con);
+/**
+ * Associates data with a connection object.
+ *
+ * @param url_con Connection object to associate data.
+ * @param data Data to be set.
+ *
+ * Associates data with a connection object, which can be retrieved later with
+ * ecore_con_url_data_get()).
+ *
+ * @see ecore_con_url_data_get()
+ */
+EAPI void ecore_con_url_data_set(Ecore_Con_Url *url_con,
+ void *data);
+/**
+ * Retrieves data associated with a Ecore_Con_Url connection object.
+ *
+ * @param url_con Connection object to retrieve data from.
+ *
+ * @return Data associated with the given object.
+ *
+ * Retrieves data associated with a Ecore_Con_Url connection object (previously
+ * set with ecore_con_url_data_set()).
+ *
+ * @see ecore_con_url_data_set()
+ */
+EAPI void * ecore_con_url_data_get(Ecore_Con_Url *url_con);
+/**
+ * Adds an additional header to the request connection object.
+ *
+ * @param url_con Connection object
+ * @param key Header key
+ * @param value Header value
+ *
+ * Adds an additional header (User-Agent, Content-Type, etc.) to the request
+ * connection object. This addition will be valid for only one
+ * ecore_con_url_get() or ecore_con_url_post() call.
+ *
+ * Some functions like ecore_con_url_time() also add headers to the request.
+ *
+ * @see ecore_con_url_get()
+ * @see ecore_con_url_post()
+ * @see ecore_con_url_additional_headers_clear()
+ */
+EAPI void ecore_con_url_additional_header_add(Ecore_Con_Url *url_con,
+ const char *key,
+ const char *value);
+/**
+ * Cleans additional headers.
+ *
+ * @param url_con Connection object to clean additional headers.
+ *
+ * Cleans additional headers associated with a connection object (previously
+ * added with ecore_con_url_additional_header_add()).
+ *
+ * @see ecore_con_url_additional_header_add()
+ * @see ecore_con_url_get()
+ * @see ecore_con_url_post()
+ */
+EAPI void ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con);
+/**
+ * Retrieves headers from last request sent.
+ *
+ * @param url_con Connection object to retrieve response headers from.
+ *
+ * Retrieves a list containing the response headers. This function should be
+ * used after an ECORE_CON_EVENT_URL_COMPLETE event (headers should normally be
+ * ready at that time).
+ *
+ * @return List of response headers. This list must not be modified by the user.
+ */
+EAPI const Eina_List * ecore_con_url_response_headers_get(Ecore_Con_Url *url_con);
+/**
+ * Setup a file for receiving response data.
+ *
+ * @param url_con Connection object to set file
+ * @param fd File descriptor associated with the file. A negative value will
+ * unset any previously set fd.
+ *
+ * Sets up a file to have response data written into. Note that
+ * ECORE_CON_EVENT_URL_DATA events will not be emitted if a file has been set to
+ * receive the response data.
+ *
+ * This call can be used to easily setup a file where the downloaded data will
+ * be saved.
+ */
+EAPI void ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd);
+/**
+ * Retrieves the number of bytes received.
+ *
+ * Retrieves the number of bytes received on the last request of the given
+ * connection object.
+ *
+ * @param url_con Connection object which the request was sent on.
+ *
+ * @return Number of bytes received on request.
+ *
+ * @see ecore_con_url_get()
+ * @see ecore_con_url_post()
+ */
+EAPI int ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con);
+/**
+ * Sets url_con to use http auth, with given username and password, "safely" or not.
+ *
+ * @param url_con Connection object to perform a request on, previously created
+ * with ecore_con_url_new() or ecore_con_url_custom_new().
+ * @param username Username to use in authentication
+ * @param password Password to use in authentication
+ * @param safe Whether to use "safer" methods (eg, NOT http basic auth)
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ *
+ * @attention Requires libcurl >= 7.19.1 to work, otherwise will always return
+ * @c 0.
+ */
+EAPI Eina_Bool ecore_con_url_httpauth_set(Ecore_Con_Url *url_con,
+ const char *username,
+ const char *password,
+ Eina_Bool safe);
+/**
+ * Sends a get request.
+ *
+ * @param url_con Connection object to perform a request on, previously created
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ *
+ * The request is performed immediately, but you need to setup event handlers
+ * for #ECORE_CON_EVENT_URL_DATA, #ECORE_CON_EVENT_URL_COMPLETE or
+ * #ECORE_CON_EVENT_URL_PROGRESS to get more information about its result.
+ *
+ * @see ecore_con_url_custom_new()
+ * @see ecore_con_url_additional_headers_clear()
+ * @see ecore_con_url_additional_header_add()
+ * @see ecore_con_url_data_set()
+ * @see ecore_con_url_data_get()
+ * @see ecore_con_url_response_headers_get()
+ * @see ecore_con_url_time()
+ * @see ecore_con_url_post()
+ */
+EAPI Eina_Bool ecore_con_url_get(Ecore_Con_Url *url_con);
+/**
+ * Sends a post request.
+ *
+ * @param url_con Connection object to perform a request on, previously created
+ * with ecore_con_url_new() or ecore_con_url_custom_new().
+ * @param data Payload (data sent on the request). Can be @c NULL.
+ * @param length Payload length. If @c -1, rely on automatic length
+ * calculation via @c strlen() on @p data.
+ * @param content_type Content type of the payload (e.g. text/xml). Can be @c
+ * NULL.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ *
+ * The request starts immediately, but you need to setup event handlers
+ * for #ECORE_CON_EVENT_URL_DATA, #ECORE_CON_EVENT_URL_COMPLETE or
+ * #ECORE_CON_EVENT_URL_PROGRESS to get more information about its result.
+ *
+ * This call won't block your main loop.
+ *
+ * @see ecore_con_url_custom_new()
+ * @see ecore_con_url_additional_headers_clear()
+ * @see ecore_con_url_additional_header_add()
+ * @see ecore_con_url_data_set()
+ * @see ecore_con_url_data_get()
+ * @see ecore_con_url_response_headers_get()
+ * @see ecore_con_url_time()
+ * @see ecore_con_url_get()
+ */
+EAPI Eina_Bool ecore_con_url_post(Ecore_Con_Url *url_con,
+ const void *data, long length,
+ const char *content_type);
+/**
+ * Sets whether HTTP requests should be conditional, dependent on
+ * modification time.
+ *
+ * @param url_con Ecore_Con_Url to act upon.
+ * @param time_condition Condition to use for HTTP requests.
+ * @param timestamp Time since 1 Jan 1970 to use in the condition.
+ *
+ * This function may set the header "If-Modified-Since" or
+ * "If-Unmodified-Since", depending on the value of @p time_condition, with the
+ * value @p timestamp.
+ *
+ * @sa ecore_con_url_get()
+ * @sa ecore_con_url_post()
+ */
+EAPI void ecore_con_url_time(Ecore_Con_Url *url_con,
+ Ecore_Con_Url_Time time_condition,
+ double timestamp);
+
+/**
+ * @brief Uploads a file to an ftp site.
+ *
+ * @param url_con The Ecore_Con_Url object to send with
+ * @param filename The path to the file to send
+ * @param user The username to log in with
+ * @param pass The password to log in with
+ * @param upload_dir The directory to which the file should be uploaded
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * Upload @p filename to an ftp server set in @p url_con using @p user
+ * and @p pass to directory @p upload_dir
+ */
+EAPI Eina_Bool ecore_con_url_ftp_upload(Ecore_Con_Url *url_con,
+ const char *filename,
+ const char *user,
+ const char *pass,
+ const char *upload_dir);
+/**
+ * Toggle libcurl's verbose output.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ * @param verbose Whether or not to enable libcurl's verbose output.
+ *
+ * If @p verbose is @c EINA_TRUE, libcurl will output a lot of verbose
+ * information about its operations, which is useful for
+ * debugging. The verbose information will be sent to stderr.
+ */
+EAPI void ecore_con_url_verbose_set(Ecore_Con_Url *url_con,
+ Eina_Bool verbose);
+/**
+ * Enable or disable EPSV extension
+ * @param url_con The Ecore_Con_Url instance which will be acted upon.
+ * @param use_epsv Boolean to enable/disable the EPSV extension.
+ */
+EAPI void ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con,
+ Eina_Bool use_epsv);
+
+/**
+ * Enables the cookie engine for subsequent HTTP requests.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ *
+ * After this function is called, cookies set by the server in HTTP responses
+ * will be parsed and stored, as well as sent back to the server in new HTTP
+ * requests.
+ *
+ * @note Even though this function is called @c ecore_con_url_cookies_init(),
+ * there is no symmetrical shutdown operation.
+ */
+EAPI void ecore_con_url_cookies_init(Ecore_Con_Url *url_con);
+/**
+ * Controls whether session cookies from previous sessions shall be loaded.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ * @param ignore If @c EINA_TRUE, ignore session cookies when loading cookies
+ * from files. If @c EINA_FALSE, all cookies will be loaded.
+ *
+ * Session cookies are cookies with no expire date set, which usually means
+ * they are removed after the current session is closed.
+ *
+ * By default, when Ecore_Con_Url loads cookies from a file, all cookies are
+ * loaded, including session cookies, which, most of the time, were supposed
+ * to be loaded and valid only for that session.
+ *
+ * If @p ignore is set to @c EINA_TRUE, when Ecore_Con_Url loads cookies from
+ * the files passed to @c ecore_con_url_cookies_file_add(), session cookies
+ * will not be loaded.
+ *
+ * @see ecore_con_url_cookies_file_add()
+ */
+EAPI void ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con,
+ Eina_Bool ignore);
+/**
+ * Clears currently loaded cookies.
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ *
+ * The cleared cookies are removed and will not be sent in subsequent HTTP
+ * requests, nor will they be written to the cookiejar file set via
+ * @c ecore_con_url_cookies_jar_file_set().
+ *
+ * @note This function will initialize the cookie engine if it has not been
+ * initialized yet.
+ * @note The cookie files set by ecore_con_url_cookies_file_add() aren't loaded
+ * immediately, just when the request is started. Thus, if you ask to
+ * clear the cookies, but has a file already set by that function, the
+ * cookies will then be loaded and you will have old cookies set. In order
+ * to don't have any old cookie set, you need to don't call
+ * ecore_con_url_cookies_file_add() ever on the @p url_con handler, and
+ * call this function to clear any cookie set by a previous request on
+ * this handler.
+ *
+ * @see ecore_con_url_cookies_session_clear()
+ * @see ecore_con_url_cookies_ignore_old_session_set()
+ */
+EAPI void ecore_con_url_cookies_clear(Ecore_Con_Url *url_con);
+/**
+ * Clears currently loaded session cookies.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ *
+ * Session cookies are cookies with no expire date set, which usually means
+ * they are removed after the current session is closed.
+ *
+ * The cleared cookies are removed and will not be sent in subsequent HTTP
+ * requests, nor will they be written to the cookiejar file set via
+ * @c ecore_con_url_cookies_jar_file_set().
+ *
+ * @note This function will initialize the cookie engine if it has not been
+ * initialized yet.
+ * @note The cookie files set by ecore_con_url_cookies_file_add() aren't loaded
+ * immediately, just when the request is started. Thus, if you ask to
+ * clear the session cookies, but has a file already set by that function,
+ * the session cookies will then be loaded and you will have old cookies
+ * set. In order to don't have any old session cookie set, you need to
+ * don't call ecore_con_url_cookies_file_add() ever on the @p url_con
+ * handler, and call this function to clear any session cookie set by a
+ * previous request on this handler. An easier way to don't use old
+ * session cookies is by using the function
+ * ecore_con_url_cookies_ignore_old_session_set().
+ *
+ * @see ecore_con_url_cookies_clear()
+ * @see ecore_con_url_cookies_ignore_old_session_set()
+ */
+EAPI void ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con);
+/**
+ * Adds a file to the list of files from which to load cookies.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ * @param file_name Name of the file that will be added to the list.
+ *
+ * Files must contain cookies defined according to two possible formats:
+ *
+ * @li HTTP-style header ("Set-Cookie: ...").
+ * @li <a href="http://www.cookiecentral.com/faq/#3.5">Netscape/Mozilla cookie data format.</a>
+ *
+ * Cookies will only be @b read from this file. If you want to save cookies to a
+ * file, use ecore_con_url_cookies_jar_file_set(). Also notice that this
+ * function supports the both types of cookie file cited above, while
+ * ecore_con_url_cookies_jar_file_set() will save only in the Netscape/Mozilla's
+ * format.
+ *
+ * Please notice that the file will not be read immediately, but rather added
+ * to a list of files that will be loaded and parsed at a later time.
+ *
+ * @note This function will initialize the cookie engine if it has not been
+ * initialized yet.
+ *
+ * @see ecore_con_url_cookies_ignore_old_session_set()
+ * @see ecore_con_url_cookies_jar_file_set()
+ */
+EAPI void ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con,
+ const char * const file_name);
+/**
+ * Sets the name of the file to which all current cookies will be written when
+ * either cookies are flushed or Ecore_Con is shut down.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ * @param cookiejar_file File to which the cookies will be written.
+ *
+ * @return @c EINA_TRUE is the file name has been set successfully,
+ * @c EINA_FALSE otherwise.
+ *
+ * Cookies are written following Netscape/Mozilla's data format, also known as
+ * cookie-jar.
+ *
+ * Cookies will only be @b saved to this file. If you need to read cookies from
+ * a file, use ecore_con_url_cookies_file_add() instead.
+ *
+ * @note This function will initialize the cookie engine if it has not been
+ * initialized yet.
+ *
+ * @see ecore_con_url_cookies_jar_write()
+ */
+EAPI Eina_Bool ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con,
+ const char * const cookiejar_file);
+/**
+ * Writes all current cookies to the cookie jar immediately.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ *
+ * A cookie-jar file must have been previously set by
+ * @c ecore_con_url_jar_file_set, otherwise nothing will be done.
+ *
+ * @note This function will initialize the cookie engine if it has not been
+ * initialized yet.
+ *
+ * @see ecore_con_url_cookies_jar_file_set()
+ */
+EAPI void ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con);
+
+EAPI void ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con,
+ Eina_Bool verify);
+EAPI int ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con,
+ const char *ca_path);
+
+/**
+ * Set HTTP proxy to use.
+ *
+ * The parameter should be a char * to a zero terminated string holding
+ * the host name or dotted IP address. To specify port number in this string,
+ * append :[port] to the end of the host name.
+ * The proxy string may be prefixed with [protocol]:// since any such prefix
+ * will be ignored.
+ * The proxy's port number may optionally be specified with the separate option.
+ * If not specified, libcurl will default to using port 1080 for proxies.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param proxy Porxy string or @c NULL to disable
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy);
+
+/**
+ * Set zero terminated username to use for proxy.
+ *
+ * if socks protocol is used for proxy, protocol should be socks5 and above.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param username Username string.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ *
+ * @see ecore_con_url_proxy_set()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username);
+
+/**
+ * Set zero terminated password to use for proxy.
+ *
+ * if socks protocol is used for proxy, protocol should be socks5 and above.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param password Password string.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on error.
+ *
+ * @see ecore_con_url_proxy_set()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password);
+
+/**
+ * Set timeout in seconds.
+ *
+ * the maximum time in seconds that you allow the ecore con url transfer
+ * operation to take. Normally, name lookups can take a considerable time
+ * and limiting operations to less than a few minutes risk aborting perfectly
+ * normal operations.
+ *
+ * @param url_con Connection object that will use the timeout.
+ * @param timeout time in seconds.
+ *
+ * @see ecore_con_url_cookies_jar_file_set()
+ *
+ * @since 1.2
+ */
+EAPI void ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout);
+
+/**
+ * Get the returned HTTP STATUS code
+ *
+ * This is used to, at any time, try to return the status code for a transmission.
+ * @param url_con Connection object
+ * @return A valid HTTP STATUS code, or 0 on failure
+ *
+ * @since 1.2
+ */
+EAPI int ecore_con_url_status_code_get(Ecore_Con_Url *url_con);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_con/Ecore_Con_Eet.h b/src/lib/ecore_con/Ecore_Con_Eet.h
new file mode 100644
index 0000000000..bdf0d2d605
--- /dev/null
+++ b/src/lib/ecore_con/Ecore_Con_Eet.h
@@ -0,0 +1,73 @@
+#ifndef _ECORE_CON_EET
+# define _ECORE_CON_EET
+
+#include <Eet.h>
+#include <Ecore.h>
+#include <Ecore_Con.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_CON_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif
+# else
+# define EAPI __declspec(dllimport)
+# endif
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+typedef struct _Ecore_Con_Eet Ecore_Con_Eet;
+typedef struct _Ecore_Con_Reply Ecore_Con_Reply;
+
+typedef void (*Ecore_Con_Eet_Data_Cb)(void *data, Ecore_Con_Reply *reply, const char *protocol_name, void *value);
+typedef void (*Ecore_Con_Eet_Raw_Data_Cb)(void *data, Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, size_t length);
+typedef Eina_Bool (*Ecore_Con_Eet_Client_Cb)(void *data, Ecore_Con_Reply *reply, Ecore_Con_Client *conn);
+typedef Eina_Bool (*Ecore_Con_Eet_Server_Cb)(void *data, Ecore_Con_Reply *reply, Ecore_Con_Server *conn);
+
+EAPI Ecore_Con_Eet *ecore_con_eet_server_new(Ecore_Con_Server *server);
+EAPI Ecore_Con_Eet *ecore_con_eet_client_new(Ecore_Con_Server *server);
+EAPI void ecore_con_eet_server_free(Ecore_Con_Eet *ece);
+
+EAPI void ecore_con_eet_register(Ecore_Con_Eet *ece, const char *name, Eet_Data_Descriptor *edd);
+
+EAPI void ecore_con_eet_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Data_Cb func, const void *data);
+EAPI void ecore_con_eet_data_callback_del(Ecore_Con_Eet *ece, const char *name);
+
+EAPI void ecore_con_eet_raw_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Raw_Data_Cb func, const void *data);
+EAPI void ecore_con_eet_raw_data_callback_del(Ecore_Con_Eet *ece, const char *name);
+
+EAPI void ecore_con_eet_client_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data);
+EAPI void ecore_con_eet_client_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data);
+
+EAPI void ecore_con_eet_client_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data);
+EAPI void ecore_con_eet_client_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data);
+
+EAPI void ecore_con_eet_server_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data);
+EAPI void ecore_con_eet_server_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data);
+
+EAPI void ecore_con_eet_server_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data);
+EAPI void ecore_con_eet_server_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data);
+
+EAPI void ecore_con_eet_data_set(Ecore_Con_Eet *ece, const void *data);
+EAPI void *ecore_con_eet_data_get(Ecore_Con_Eet *ece);
+
+EAPI Ecore_Con_Eet *ecore_con_eet_reply(Ecore_Con_Reply *reply);
+EAPI void ecore_con_eet_send(Ecore_Con_Reply *reply, const char *protocol_name, void *value);
+EAPI void ecore_con_eet_raw_send(Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, unsigned int length);
+
+#endif
diff --git a/src/lib/ecore_con/dns.c b/src/lib/ecore_con/dns.c
new file mode 100644
index 0000000000..b50d306dc6
--- /dev/null
+++ b/src/lib/ecore_con/dns.c
@@ -0,0 +1,7878 @@
+/* ==========================================================================
+ * dns.c - Recursive, Reentrant DNS Resolver.
+ * --------------------------------------------------------------------------
+ * Copyright (c) 2008, 2009, 2010 William Ahern
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ==========================================================================
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if !defined(__FreeBSD__)
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+
+#undef _BSD_SOURCE
+#define _BSD_SOURCE
+
+#undef _DARWIN_C_SOURCE
+#define _DARWIN_C_SOURCE
+
+#undef _NETBSD_SOURCE
+#define _NETBSD_SOURCE
+#endif
+
+#include <stddef.h> /* offsetof() */
+#include <stdint.h> /* uint32_t */
+#include <stdlib.h> /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
+#include <stdio.h> /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
+
+#include <string.h> /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
+#include <strings.h> /* strcasecmp(3) strncasecmp(3) */
+
+#include <ctype.h> /* isspace(3) isdigit(3) */
+
+#include <time.h> /* time_t time(2) */
+
+#include <signal.h> /* sig_atomic_t */
+
+#include <errno.h> /* errno EINVAL ENOENT */
+
+#undef NDEBUG
+#include <assert.h> /* assert(3) */
+
+#if _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h> /* FD_SETSIZE socklen_t */
+#include <sys/select.h> /* FD_ZERO FD_SET fd_set select(2) */
+#include <sys/socket.h> /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
+
+#if defined(AF_UNIX)
+#include <sys/un.h> /* struct sockaddr_un */
+#endif
+
+#include <fcntl.h> /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
+
+#include <unistd.h> /* gethostname(3) close(2) */
+
+#include <poll.h> /* POLLIN POLLOUT */
+
+#include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
+
+#include <arpa/inet.h> /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
+
+#include <netdb.h> /* struct addrinfo */
+#endif
+
+#include "dns.h"
+
+
+/*
+ * S T A N D A R D M A C R O S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b))? (a) : (b))
+#endif
+
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b))? (a) : (b))
+#endif
+
+
+#ifndef lengthof
+#define lengthof(a) (sizeof (a) / sizeof (a)[0])
+#endif
+
+#ifndef endof
+#define endof(a) (&(a)[lengthof((a))])
+#endif
+
+
+/*
+ * D E B U G M A C R O S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int dns_debug = 0;
+
+#if DNS_DEBUG
+
+#undef DNS_DEBUG
+#define DNS_DEBUG dns_debug
+
+#define DNS_SAY_(fmt, ...) \
+ do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
+#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
+#define DNS_HAI DNS_SAY("HAI")
+
+#define DNS_SHOW_(P, fmt, ...) do { \
+ if (DNS_DEBUG > 1) { \
+ fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
+ fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
+ dns_p_dump((P), stderr); \
+ fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
+ } \
+} while (0)
+
+#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
+
+#else /* !DNS_DEBUG */
+
+#undef DNS_DEBUG
+#define DNS_DEBUG 0
+
+#define DNS_SAY(...)
+#define DNS_HAI
+#define DNS_SHOW(...)
+
+#endif /* DNS_DEBUG */
+
+
+/*
+ * V E R S I O N R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const char *dns_vendor(void) {
+ return DNS_VENDOR;
+} /* dns_vendor() */
+
+
+int dns_v_rel(void) {
+ return DNS_V_REL;
+} /* dns_v_rel() */
+
+
+int dns_v_abi(void) {
+ return DNS_V_ABI;
+} /* dns_v_abi() */
+
+
+int dns_v_api(void) {
+ return DNS_V_API;
+} /* dns_v_api() */
+
+
+/*
+ * E R R O R R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if _WIN32
+
+#define DNS_EINTR WSAEINTR
+#define DNS_EINPROGRESS WSAEINPROGRESS
+#define DNS_EISCONN WSAEISCONN
+#define DNS_EWOULDBLOCK WSAEWOULDBLOCK
+#define DNS_EALREADY WSAEALREADY
+#define DNS_EAGAIN EAGAIN
+#define DNS_ETIMEDOUT WSAETIMEDOUT
+
+#define dns_syerr() ((int)GetLastError())
+#define dns_soerr() ((int)WSAGetLastError())
+
+#else
+
+#define DNS_EINTR EINTR
+#define DNS_EINPROGRESS EINPROGRESS
+#define DNS_EISCONN EISCONN
+#define DNS_EWOULDBLOCK EWOULDBLOCK
+#define DNS_EALREADY EALREADY
+#define DNS_EAGAIN EAGAIN
+#define DNS_ETIMEDOUT ETIMEDOUT
+
+#define dns_syerr() errno
+#define dns_soerr() errno
+
+#endif
+
+
+const char *dns_strerror(int error) {
+ switch (error) {
+ case DNS_ENOBUFS:
+ return "DNS packet buffer too small";
+ case DNS_EILLEGAL:
+ return "Illegal DNS RR name or data";
+ case DNS_EORDER:
+ return "Attempt to push RR out of section order";
+ case DNS_ESECTION:
+ return "Invalid section specified";
+ case DNS_EUNKNOWN:
+ return "Unknown DNS error";
+ default:
+ return strerror(error);
+ } /* switch() */
+} /* dns_strerror() */
+
+
+/*
+ * A T O M I C R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static unsigned dns_atomic_inc(dns_atomic_t *i) {
+ return (*i)++;
+} /* dns_atomic_inc() */
+
+
+static unsigned dns_atomic_dec(dns_atomic_t *i) {
+ return (*i)--;
+} /* dns_atomic_dec() */
+
+
+/*
+ * C R Y P T O R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * P R N G
+ */
+
+#ifndef DNS_RANDOM
+#if defined(HAVE_ARC4RANDOM) \
+ || defined(__OpenBSD__) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__APPLE__)
+#define DNS_RANDOM arc4random
+#elif __linux
+#define DNS_RANDOM random
+#else
+#define DNS_RANDOM rand
+#endif
+#endif
+
+#define DNS_RANDOM_arc4random 1
+#define DNS_RANDOM_random 2
+#define DNS_RANDOM_rand 3
+#define DNS_RANDOM_RAND_bytes 4
+
+#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
+
+#if DNS_RANDOM_OPENSSL
+#include <openssl/rand.h>
+#endif
+
+static unsigned dns_random_(void) {
+#if DNS_RANDOM_OPENSSL
+ unsigned r;
+
+ assert(1 == RAND_bytes((unsigned char *)&r, sizeof r));
+
+ return r;
+#else
+ return DNS_RANDOM();
+#endif
+} /* dns_random_() */
+
+unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_;
+
+
+/*
+ * P E R M U T A T I O N G E N E R A T O R
+ */
+
+#define DNS_K_TEA_KEY_SIZE 16
+#define DNS_K_TEA_BLOCK_SIZE 8
+#define DNS_K_TEA_CYCLES 32
+#define DNS_K_TEA_MAGIC 0x9E3779B9U
+
+struct dns_k_tea {
+ uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
+ unsigned cycles;
+}; /* struct dns_k_tea */
+
+
+static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
+ memcpy(tea->key, key, sizeof tea->key);
+
+ tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
+} /* dns_k_tea_init() */
+
+
+static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
+ uint32_t y, z, sum, n;
+
+ y = v[0];
+ z = v[1];
+ sum = 0;
+
+ for (n = 0; n < tea->cycles; n++) {
+ sum += DNS_K_TEA_MAGIC;
+ y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
+ z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
+ }
+
+ w[0] = y;
+ w[1] = z;
+
+ return /* void */;
+} /* dns_k_tea_encrypt() */
+
+
+/*
+ * Permutation generator, based on a Luby-Rackoff Feistel construction.
+ *
+ * Specifically, this is a generic balanced Feistel block cipher using TEA
+ * (another block cipher) as the pseudo-random function, F. At best it's as
+ * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
+ * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
+ * simple.
+ *
+ * The generator can create a permutation of any set of numbers, as long as
+ * the size of the set is an even power of 2. This limitation arises either
+ * out of an inherent property of balanced Feistel constructions, or by my
+ * own ignorance. I'll tackle an unbalanced construction after I wrap my
+ * head around Schneier and Kelsey's paper.
+ *
+ * CAVEAT EMPTOR. IANAC.
+ */
+#define DNS_K_PERMUTOR_ROUNDS 8
+
+struct dns_k_permutor {
+ unsigned stepi, length, limit;
+ unsigned shift, mask, rounds;
+
+ struct dns_k_tea tea;
+}; /* struct dns_k_permutor */
+
+
+static inline unsigned dns_k_permutor_powof(unsigned n) {
+ unsigned m, i = 0;
+
+ for (m = 1; m < n; m <<= 1, i++)
+ ;;
+
+ return i;
+} /* dns_k_permutor_powof() */
+
+static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
+ uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
+ unsigned width, i;
+
+ p->stepi = 0;
+
+ p->length = (high - low) + 1;
+ p->limit = high;
+
+ width = dns_k_permutor_powof(p->length);
+ width += width % 2;
+
+ p->shift = width / 2;
+ p->mask = (1U << p->shift) - 1;
+ p->rounds = DNS_K_PERMUTOR_ROUNDS;
+
+ for (i = 0; i < lengthof(key); i++)
+ key[i] = dns_random();
+
+ dns_k_tea_init(&p->tea, key, 0);
+
+ return /* void */;
+} /* dns_k_permutor_init() */
+
+
+static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
+ uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
+
+ memset(in, '\0', sizeof in);
+
+ in[0] = k;
+ in[1] = x;
+
+ dns_k_tea_encrypt(&p->tea, in, out);
+
+ return p->mask & out[0];
+} /* dns_k_permutor_F() */
+
+
+static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
+ unsigned l[2], r[2];
+ unsigned i;
+
+ i = 0;
+ l[i] = p->mask & (n >> p->shift);
+ r[i] = p->mask & (n >> 0);
+
+ do {
+ l[(i + 1) % 2] = r[i % 2];
+ r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
+
+ i++;
+ } while (i < p->rounds - 1);
+
+ return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
+} /* dns_k_permutor_E() */
+
+static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
+ unsigned n;
+
+ do {
+ n = dns_k_permutor_E(p, p->stepi++);
+ } while (n >= p->length);
+
+ return n + (p->limit + 1 - p->length);
+} /* dns_k_permutor_step() */
+
+
+/*
+ * Simple permutation box. Useful for shuffling rrsets from an iterator.
+ * Uses AES s-box to provide good diffusion.
+ *
+ * Seems to pass muster under runs test.
+ *
+ * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
+ * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
+ * library(lawstat)
+ * runs.test(scan(file="/tmp/out"))
+ * EOF
+ */
+static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
+ static const unsigned char sbox[256] =
+ { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
+ unsigned char a, b;
+ unsigned i;
+
+ a = 0xff & (n >> 0);
+ b = 0xff & (n >> 8);
+
+ for (i = 0; i < 4; i++) {
+ a ^= 0xff & s;
+ a = sbox[a] ^ b;
+ b = sbox[b] ^ a;
+ s >>= 8;
+ }
+
+ return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
+} /* dns_k_shuffle16() */
+
+
+/*
+ * U T I L I T Y R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Monotonic Time
+ *
+ */
+static time_t dns_now(void) {
+ /* XXX: Assumes sizeof (time_t) <= sizeof (sig_atomic_t) */
+ static volatile sig_atomic_t last, tick;
+ volatile sig_atomic_t tmp_last, tmp_tick;
+ time_t now;
+
+ time(&now);
+
+ tmp_last = last;
+
+ if (now > tmp_last) {
+ tmp_tick = tick;
+ tmp_tick += now - tmp_last;
+ tick = tmp_tick;
+ }
+
+ last = now;
+
+ return tick;
+} /* dns_now() */
+
+static time_t dns_elapsed(time_t from) {
+ time_t now = dns_now();
+
+ return (now > from)? now - from : 0;
+} /* dns_elpased() */
+
+
+static size_t dns_af_len(int af) {
+ static const size_t table[AF_MAX] = {
+ [AF_INET6] = sizeof (struct sockaddr_in6),
+ [AF_INET] = sizeof (struct sockaddr_in),
+#if defined(AF_UNIX) && !defined(_WIN32)
+ [AF_UNIX] = sizeof (struct sockaddr_un),
+#endif
+ };
+
+ return table[af];
+} /* dns_af_len() */
+
+#define dns_sa_len(sa) dns_af_len(dns_sa_family(sa))
+
+
+#define DNS_SA_NOPORT &dns_sa_noport
+static unsigned short dns_sa_noport;
+
+unsigned short *dns_sa_port(int af, void *sa) {
+ switch (af) {
+ case AF_INET6:
+ return &((struct sockaddr_in6 *)sa)->sin6_port;
+ case AF_INET:
+ return &((struct sockaddr_in *)sa)->sin_port;
+ default:
+ return DNS_SA_NOPORT;
+ }
+} /* dns_sa_port() */
+
+
+void *dns_sa_addr(int af, void *sa) {
+ switch (af) {
+ case AF_INET6:
+ return &((struct sockaddr_in6 *)sa)->sin6_addr;
+ case AF_INET:
+ return &((struct sockaddr_in *)sa)->sin_addr;
+ default:
+ return 0;
+ }
+} /* dns_sa_addr() */
+
+
+#if _WIN32
+static int dns_inet_pton(int af, const void *src, void *dst) {
+ union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
+
+ u.sin.sin_family = af;
+
+ if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
+ return -1;
+
+ switch (af) {
+ case AF_INET6:
+ *(struct in6_addr *)dst = u.sin6.sin6_addr;
+
+ return 1;
+ case AF_INET:
+ *(struct in_addr *)dst = u.sin.sin_addr;
+
+ return 1;
+ default:
+ return 0;
+ }
+} /* dns_inet_pton() */
+
+const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
+ union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
+
+ /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
+ memset(&u, 0, sizeof u);
+
+ u.sin.sin_family = af;
+
+ switch (af) {
+ case AF_INET6:
+ u.sin6.sin6_addr = *(struct in6_addr *)src;
+ break;
+ case AF_INET:
+ u.sin.sin_addr = *(struct in_addr *)src;
+
+ break;
+ default:
+ return 0;
+ }
+
+ if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
+ return 0;
+
+ return dst;
+} /* dns_inet_ntop() */
+#endif
+
+
+size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
+ char *d = dst;
+ char *e = &dst[lim];
+ const char *s = src;
+
+ if (d < e) {
+ do {
+ if ('\0' == (*d++ = *s++))
+ return s - src - 1;
+ } while (d < e);
+
+ d[-1] = '\0';
+ }
+
+ while (*s++ != '\0')
+ ;;
+
+ return s - src - 1;
+} /* dns_strlcpy() */
+
+
+size_t dns_strlcat(char *dst, const char *src, size_t lim) {
+ char *d = memchr(dst, '\0', lim);
+ char *e = &dst[lim];
+ const char *s = src;
+ const char *p;
+
+ if (d && d < e) {
+ do {
+ if ('\0' == (*d++ = *s++))
+ return d - dst - 1;
+ } while (d < e);
+
+ d[-1] = '\0';
+ }
+
+ p = s;
+
+ while (*s++ != '\0')
+ ;;
+
+ return lim + (s - p - 1);
+} /* dns_strlcat() */
+
+
+#if defined(_WIN32) || defined(__SUNPRO_C)
+
+static char *dns_strsep(char **sp, const char *delim) {
+ char *p;
+
+ if (!(p = *sp))
+ return 0;
+
+ *sp += strcspn(p, delim);
+
+ if (**sp != '\0') {
+ **sp = '\0';
+ ++*sp;
+ } else
+ *sp = NULL;
+
+ return p;
+} /* dns_strsep() */
+
+#else
+#define dns_strsep(...) strsep(__VA_ARGS__)
+#endif
+
+
+#if _WIN32
+#define strcasecmp(...) _stricmp(__VA_ARGS__)
+#define strncasecmp(...) _strnicmp(__VA_ARGS__)
+#endif
+
+
+static int dns_poll(int fd, short events, int timeout) {
+ fd_set rset, wset;
+
+ if (!events)
+ return 0;
+
+ assert(fd >= 0 && fd < FD_SETSIZE);
+
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+
+ if (events & DNS_POLLIN)
+ FD_SET(fd, &rset);
+
+ if (events & DNS_POLLOUT)
+ FD_SET(fd, &wset);
+
+ select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
+
+ return 0;
+} /* dns_poll() */
+
+
+/*
+ * P A C K E T R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
+ unsigned count;
+
+ switch (section) {
+ case DNS_S_QD:
+ return ntohs(dns_header(P)->qdcount);
+ case DNS_S_AN:
+ return ntohs(dns_header(P)->ancount);
+ case DNS_S_NS:
+ return ntohs(dns_header(P)->nscount);
+ case DNS_S_AR:
+ return ntohs(dns_header(P)->arcount);
+ default:
+ count = 0;
+
+ if (section & DNS_S_QD)
+ count += ntohs(dns_header(P)->qdcount);
+ if (section & DNS_S_AN)
+ count += ntohs(dns_header(P)->ancount);
+ if (section & DNS_S_NS)
+ count += ntohs(dns_header(P)->nscount);
+ if (section & DNS_S_AR)
+ count += ntohs(dns_header(P)->arcount);
+
+ return count;
+ }
+} /* dns_p_count() */
+
+
+struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
+ if (!P)
+ return 0;
+
+ assert(size >= offsetof(struct dns_packet, data) + 12);
+
+ memset(P, 0, sizeof *P);
+ P->size = size - offsetof(struct dns_packet, data);
+ P->end = 12;
+
+ memset(P->data, '\0', 12);
+
+ return P;
+} /* dns_p_init() */
+
+
+static unsigned short dns_p_qend(struct dns_packet *P) {
+ unsigned short qend = 12;
+ unsigned i, count = dns_p_count(P, DNS_S_QD);
+
+ for (i = 0; i < count && qend < P->end; i++) {
+ if (P->end == (qend = dns_d_skip(qend, P)))
+ goto invalid;
+
+ if (P->end - qend < 4)
+ goto invalid;
+
+ qend += 4;
+ }
+
+ return MIN(qend, P->end);
+invalid:
+ return P->end;
+} /* dns_p_qend() */
+
+
+struct dns_packet *dns_p_make(size_t len, int *error) {
+ struct dns_packet *P;
+ size_t size = dns_p_calcsize(len);
+
+ if (!(P = dns_p_init(malloc(size), size)))
+ *error = dns_syerr();
+
+ return P;
+} /* dns_p_make() */
+
+
+int dns_p_grow(struct dns_packet **P) {
+ struct dns_packet *tmp;
+ size_t size;
+ int error;
+
+ if (!*P) {
+ if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
+ return error;
+
+ return 0;
+ }
+
+ size = dns_p_sizeof(*P);
+ size |= size >> 1;
+ size |= size >> 2;
+ size |= size >> 4;
+ size |= size >> 8;
+ size++;
+
+ if (size > 65536)
+ return DNS_ENOBUFS;
+
+ if (!(tmp = realloc(*P, dns_p_calcsize(size))))
+ return dns_syerr();
+
+ tmp->size = size;
+ *P = tmp;
+
+ return 0;
+} /* dns_p_grow() */
+
+
+struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
+ if (!P)
+ return 0;
+
+ P->end = MIN(P->size, P0->end);
+
+ memcpy(P->data, P0->data, P->end);
+
+ return P;
+} /* dns_p_copy() */
+
+
+struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
+ size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
+ struct dns_packet *M;
+ enum dns_section section;
+ struct dns_rr rr, mr;
+ int error, copy;
+
+ if (!A && B) {
+ A = B;
+ Amask = Bmask;
+ B = 0;
+ }
+
+merge:
+ if (!(M = dns_p_make(bufsiz, &error)))
+ goto error;
+
+ for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
+ if (A && (section & Amask)) {
+ dns_rr_foreach(&rr, A, .section = section) {
+ if ((error = dns_rr_copy(M, &rr, A)))
+ goto error;
+ }
+ }
+
+ if (B && (section & Bmask)) {
+ dns_rr_foreach(&rr, B, .section = section) {
+ copy = 1;
+
+ dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
+ if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
+ break;
+ }
+
+ if (copy && (error = dns_rr_copy(M, &rr, B)))
+ goto error;
+ }
+ }
+ }
+
+ return M;
+error:
+ free(M); M = 0;
+
+ if (error == DNS_ENOBUFS && bufsiz < 65535) {
+ bufsiz = MIN(65535, bufsiz * 2);
+
+ goto merge;
+ }
+
+ *error_ = error;
+
+ return 0;
+} /* dns_p_merge() */
+
+
+static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
+
+void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
+ unsigned short lp, lptr, i;
+
+ lp = dn;
+
+ while (lp < P->end) {
+ if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
+ lptr = ((0x3f & P->data[lp + 0]) << 8)
+ | ((0xff & P->data[lp + 1]) << 0);
+
+ for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
+ if (P->dict[i] == lptr) {
+ P->dict[i] = dn;
+
+ return;
+ }
+ }
+ }
+
+ lp = dns_l_skip(lp, P->data, P->end);
+ }
+
+ for (i = 0; i < lengthof(P->dict); i++) {
+ if (!P->dict[i]) {
+ P->dict[i] = dn;
+
+ break;
+ }
+ }
+} /* dns_p_dictadd() */
+
+
+int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) {
+ size_t end = P->end;
+ int error;
+
+ if ((error = dns_d_push(P, dn, dnlen)))
+ goto error;
+
+ if (P->size - P->end < 4)
+ goto nobufs;
+
+ P->data[P->end++] = 0xff & (type >> 8);
+ P->data[P->end++] = 0xff & (type >> 0);
+
+ P->data[P->end++] = 0xff & (class >> 8);
+ P->data[P->end++] = 0xff & (class >> 0);
+
+ if (section == DNS_S_QD)
+ goto update;
+
+ if (P->size - P->end < 6)
+ goto nobufs;
+
+ P->data[P->end++] = 0x7f & (ttl >> 24);
+ P->data[P->end++] = 0xff & (ttl >> 16);
+ P->data[P->end++] = 0xff & (ttl >> 8);
+ P->data[P->end++] = 0xff & (ttl >> 0);
+
+ if ((error = dns_any_push(P, (union dns_any *)any, type)))
+ goto error;
+
+update:
+ switch (section) {
+ case DNS_S_QD:
+ if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
+ goto order;
+
+ if (!P->qd.base && (error = dns_p_study(P)))
+ goto error;
+
+ dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1);
+
+ P->qd.end = P->end;
+ P->an.base = P->end;
+ P->an.end = P->end;
+ P->ns.base = P->end;
+ P->ns.end = P->end;
+ P->ar.base = P->end;
+ P->ar.end = P->end;
+
+ break;
+ case DNS_S_AN:
+ if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
+ goto order;
+
+ if (!P->an.base && (error = dns_p_study(P)))
+ goto error;
+
+ dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1);
+
+ P->an.end = P->end;
+ P->ns.base = P->end;
+ P->ns.end = P->end;
+ P->ar.base = P->end;
+ P->ar.end = P->end;
+
+ break;
+ case DNS_S_NS:
+ if (dns_p_count(P, DNS_S_AR))
+ goto order;
+
+ if (!P->ns.base && (error = dns_p_study(P)))
+ goto error;
+
+ dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1);
+
+ P->ns.end = P->end;
+ P->ar.base = P->end;
+ P->ar.end = P->end;
+
+ break;
+ case DNS_S_AR:
+ if (!P->ar.base && (error = dns_p_study(P)))
+ goto error;
+
+ dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1);
+
+ P->ar.end = P->end;
+
+ break;
+ default:
+ error = DNS_ESECTION;
+
+ goto error;
+ } /* switch() */
+
+ return 0;
+nobufs:
+ error = DNS_ENOBUFS;
+
+ goto error;
+order:
+ error = DNS_EORDER;
+
+ goto error;
+error:
+ P->end = end;
+
+ return error;
+} /* dns_p_push() */
+
+
+static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
+ enum dns_section section;
+ struct dns_rr rr;
+ int error;
+ union dns_any any;
+ char pretty[sizeof any * 2];
+ size_t len;
+
+ fputs(";; [HEADER]\n", fp);
+ fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr);
+ fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
+ fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
+ fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
+ fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
+ fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
+ fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
+
+ section = 0;
+
+ while (dns_rr_grep(&rr, 1, I, P, &error)) {
+ if (section != rr.section)
+ fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
+
+ if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
+ fprintf(fp, "%s\n", pretty);
+
+ section = rr.section;
+ }
+} /* dns_p_dump3() */
+
+
+void dns_p_dump(struct dns_packet *P, FILE *fp) {
+ dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
+} /* dns_p_dump() */
+
+
+static void dns_s_unstudy(struct dns_s_memo *m)
+ { m->base = 0; m->end = 0; }
+
+static void dns_p_unstudy(struct dns_packet *P) {
+ dns_s_unstudy(&P->qd);
+ dns_s_unstudy(&P->an);
+ dns_s_unstudy(&P->ns);
+ dns_s_unstudy(&P->ar);
+} /* dns_p_unstudy() */
+
+static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) {
+ unsigned short count, rp;
+
+ count = dns_p_count(P, section);
+
+ for (rp = base; count && rp < P->end; count--)
+ rp = dns_rr_skip(rp, P);
+
+ m->base = base;
+ m->end = rp;
+
+ return 0;
+} /* dns_s_study() */
+
+int dns_p_study(struct dns_packet *P) {
+ int error;
+
+ if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P)))
+ goto error;
+
+ if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P)))
+ goto error;
+
+ if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P)))
+ goto error;
+
+ if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P)))
+ goto error;
+
+ return 0;
+error:
+ dns_p_unstudy(P);
+
+ return error;
+} /* dns_p_study() */
+
+
+/*
+ * D O M A I N N A M E R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef DNS_D_MAXPTRS
+#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
+#endif
+
+static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
+ unsigned short len;
+ unsigned nptrs = 0;
+
+retry:
+ if (src >= end)
+ goto invalid;
+
+ switch (0x03 & (data[src] >> 6)) {
+ case 0x00:
+ len = (0x3f & (data[src++]));
+
+ if (end - src < len)
+ goto invalid;
+
+ if (lim > 0) {
+ memcpy(dst, &data[src], MIN(lim, len));
+
+ dst[MIN(lim - 1, len)] = '\0';
+ }
+
+ *nxt = src + len;
+
+ return len;
+ case 0x01:
+ goto invalid;
+ case 0x02:
+ goto invalid;
+ case 0x03:
+ if (++nptrs > DNS_D_MAXPTRS)
+ goto invalid;
+
+ if (end - src < 2)
+ goto invalid;
+
+ src = ((0x3f & data[src + 0]) << 8)
+ | ((0xff & data[src + 1]) << 0);
+
+ goto retry;
+ } /* switch() */
+
+ /* NOT REACHED */
+invalid:
+ *nxt = end;
+
+ return 0;
+} /* dns_l_expand() */
+
+
+static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
+ unsigned short len;
+
+ if (src >= end)
+ goto invalid;
+
+ switch (0x03 & (data[src] >> 6)) {
+ case 0x00:
+ len = (0x3f & (data[src++]));
+
+ if (end - src < len)
+ goto invalid;
+
+ return (len)? src + len : end;
+ case 0x01:
+ goto invalid;
+ case 0x02:
+ goto invalid;
+ case 0x03:
+ return end;
+ } /* switch() */
+
+ /* NOT REACHED */
+invalid:
+ return end;
+} /* dns_l_skip() */
+
+
+size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
+ unsigned char *dst = dst_;
+ const unsigned char *src = src_;
+ size_t dp = 0, sp = 0;
+ int lc;
+
+ /* trim any leading dot(s) */
+ while (sp < len && src[sp] == '.')
+ sp++;
+
+ for (lc = 0; sp < len; lc = src[sp]) {
+ if (dp < lim)
+ dst[dp] = src[sp];
+
+ sp++;
+ dp++;
+
+ /* trim extra dot(s) */
+ while (sp < len && src[sp] == '.')
+ sp++;
+ }
+
+ if ((flags & DNS_D_ANCHOR) && lc != '.') {
+ if (dp < lim)
+ dst[dp] = '.';
+
+ dp++;
+ }
+
+ if (lim > 0)
+ dst[MIN(dp, lim - 1)] = '\0';
+
+ return dp;
+} /* dns_d_trim() */
+
+
+char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
+ if (flags & DNS_D_TRIM) {
+ dns_d_trim(dst, lim, src, len, flags);
+ } if (flags & DNS_D_ANCHOR) {
+ dns_d_anchor(dst, lim, src, len);
+ } else {
+ memmove(dst, src, MIN(lim, len));
+
+ if (lim > 0)
+ ((char *)dst)[MIN(len, lim - 1)] = '\0';
+ }
+
+ return dst;
+} /* dns_d_init() */
+
+
+size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
+ if (len == 0)
+ return 0;
+
+ memmove(dst, src, MIN(lim, len));
+
+ if (((const char *)src)[len - 1] != '.') {
+ if (len < lim)
+ ((char *)dst)[len] = '.';
+ len++;
+ }
+
+ if (lim > 0)
+ ((char *)dst)[MIN(lim - 1, len)] = '\0';
+
+ return len;
+} /* dns_d_anchor() */
+
+
+size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
+ const char *dot;
+
+ /* XXX: Skip any leading dot. Handles cleaving root ".". */
+ if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
+ return 0;
+
+ len -= dot - (const char *)src;
+
+ /* XXX: Unless root, skip the label's trailing dot. */
+ if (len > 1) {
+ src = ++dot;
+ len--;
+ } else
+ src = dot;
+
+ memmove(dst, src, MIN(lim, len));
+
+ if (lim > 0)
+ ((char *)dst)[MIN(lim - 1, len)] = '\0';
+
+ return len;
+} /* dns_d_cleave() */
+
+
+size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error EINA_UNUSED) {
+ struct { unsigned char *b; size_t p, x; } dst, src;
+ unsigned char ch = '.';
+
+ dst.b = dst_;
+ dst.p = 0;
+ dst.x = 1;
+
+ src.b = (unsigned char *)src_;
+ src.p = 0;
+ src.x = 0;
+
+ while (src.x < len) {
+ ch = src.b[src.x];
+
+ if (ch == '.') {
+ if (dst.p < lim)
+ dst.b[dst.p] = (0x3f & (src.x - src.p));
+
+ dst.p = dst.x++;
+ src.p = ++src.x;
+ } else {
+ if (dst.x < lim)
+ dst.b[dst.x] = ch;
+
+ dst.x++;
+ src.x++;
+ }
+ } /* while() */
+
+ if (src.x > src.p) {
+ if (dst.p < lim)
+ dst.b[dst.p] = (0x3f & (src.x - src.p));
+
+ dst.p = dst.x;
+ }
+
+ if (dst.p > 1) {
+ if (dst.p < lim)
+ dst.b[dst.p] = 0x00;
+
+ dst.p++;
+ }
+
+#if 1
+ if (dst.p < lim) {
+ struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
+ unsigned i;
+
+ a.p = 0;
+
+ while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
+ for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
+ b.p = P->dict[i];
+
+ while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
+ a.y = a.x;
+ b.y = b.x;
+
+ while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
+ a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
+ b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
+ }
+
+ if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
+ dst.b[a.p++] = 0xc0
+ | (0x3f & (b.p >> 8));
+ dst.b[a.p++] = (0xff & (b.p >> 0));
+
+ return a.p;
+ }
+
+ b.p = b.x;
+ } /* while() */
+ } /* for() */
+
+ a.p = a.x;
+ } /* while() */
+ } /* if () */
+#endif
+
+ return dst.p;
+} /* dns_d_comp() */
+
+
+unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
+ unsigned short len;
+
+ while (src < P->end) {
+ switch (0x03 & (P->data[src] >> 6)) {
+ case 0x00: /* FOLLOWS */
+ len = (0x3f & P->data[src++]);
+
+ if (0 == len) {
+/* success ==> */ return src;
+ } else if (P->end - src > len) {
+ src += len;
+
+ break;
+ } else
+ goto invalid;
+
+ /* NOT REACHED */
+ case 0x01: /* RESERVED */
+ goto invalid;
+ case 0x02: /* RESERVED */
+ goto invalid;
+ case 0x03: /* POINTER */
+ if (P->end - src < 2)
+ goto invalid;
+
+ src += 2;
+
+/* success ==> */ return src;
+ } /* switch() */
+ } /* while() */
+
+invalid:
+//assert(0);
+ return P->end;
+} /* dns_d_skip() */
+
+
+#include <stdio.h>
+
+size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
+ size_t dstp = 0;
+ unsigned nptrs = 0;
+ unsigned char len;
+
+ while (src < P->end) {
+ switch ((0x03 & (P->data[src] >> 6))) {
+ case 0x00: /* FOLLOWS */
+ len = (0x3f & P->data[src]);
+
+ if (0 == len) {
+ if (dstp == 0) {
+ if (dstp < lim)
+ ((unsigned char *)dst)[dstp] = '.';
+
+ dstp++;
+ }
+
+ /* NUL terminate */
+ if (lim > 0)
+ ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
+
+/* success ==> */ return dstp;
+ }
+
+ src++;
+
+ if (P->end - src < len)
+ goto toolong;
+
+ if (dstp < lim)
+ memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp));
+
+ src += len;
+ dstp += len;
+
+ if (dstp < lim)
+ ((unsigned char *)dst)[dstp] = '.';
+
+ dstp++;
+
+ nptrs = 0;
+
+ continue;
+ case 0x01: /* RESERVED */
+ goto reserved;
+ case 0x02: /* RESERVED */
+ goto reserved;
+ case 0x03: /* POINTER */
+ if (++nptrs > DNS_D_MAXPTRS)
+ goto toolong;
+
+ if (P->end - src < 2)
+ goto toolong;
+
+ src = ((0x3f & P->data[src + 0]) << 8)
+ | ((0xff & P->data[src + 1]) << 0);
+
+ continue;
+ } /* switch() */
+ } /* while() */
+
+toolong:
+ *error = DNS_EILLEGAL;
+
+ if (lim > 0)
+ ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
+
+ return 0;
+reserved:
+ *error = DNS_EILLEGAL;
+
+ if (lim > 0)
+ ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0';
+
+ return 0;
+} /* dns_d_expand() */
+
+
+int dns_d_push(struct dns_packet *P, const void *dn, size_t len) {
+ size_t lim = P->size - P->end;
+ unsigned dp = P->end;
+ int error;
+
+ len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
+
+ if (len == 0)
+ return error;
+ if (len > lim)
+ return DNS_ENOBUFS;
+
+ P->end += len;
+
+ dns_p_dictadd(P, dp);
+
+ return 0;
+} /* dns_d_push() */
+
+
+size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
+ char host[DNS_D_MAXNAME + 1];
+ struct dns_rr_i i;
+ struct dns_rr rr;
+ unsigned depth;
+ int error;
+
+ if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
+ { error = ENAMETOOLONG; goto error; }
+
+ for (depth = 0; depth < 7; depth++) {
+ dns_rr_i_init(memset(&i, 0, sizeof i), P);
+
+ i.section = DNS_S_ALL & ~DNS_S_QD;
+ i.name = host;
+ i.type = DNS_T_CNAME;
+
+ if (!dns_rr_grep(&rr, 1, &i, P, &error))
+ break;
+
+ if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
+ goto error;
+ }
+
+ return dns_strlcpy(dst, host, lim);
+error:
+ *error_ = error;
+
+ return 0;
+} /* dns_d_cname() */
+
+
+/*
+ * R E S O U R C E R E C O R D R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
+ unsigned char dn[DNS_D_MAXNAME + 1];
+ union dns_any any;
+ size_t len;
+ int error;
+
+ if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
+ return error;
+ else if (len >= sizeof dn)
+ return DNS_EILLEGAL;
+
+ if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
+ return error;
+
+ return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
+} /* dns_rr_copy() */
+
+
+int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
+ unsigned short p = src;
+
+ if (src >= P->end)
+ goto invalid;
+
+ rr->dn.p = p;
+ rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
+
+ if (P->end - p < 4)
+ goto invalid;
+
+ rr->type = ((0xff & P->data[p + 0]) << 8)
+ | ((0xff & P->data[p + 1]) << 0);
+
+ rr->class = ((0xff & P->data[p + 2]) << 8)
+ | ((0xff & P->data[p + 3]) << 0);
+
+ p += 4;
+
+ if (src < dns_p_qend(P)) {
+ rr->section = DNS_S_QUESTION;
+
+ rr->ttl = 0;
+ rr->rd.p = 0;
+ rr->rd.len = 0;
+
+ return 0;
+ }
+
+ if (P->end - p < 4)
+ goto invalid;
+
+ rr->ttl = ((0x7f & P->data[p + 0]) << 24)
+ | ((0xff & P->data[p + 1]) << 16)
+ | ((0xff & P->data[p + 2]) << 8)
+ | ((0xff & P->data[p + 3]) << 0);
+
+ p += 4;
+
+ if (P->end - p < 2)
+ goto invalid;
+
+ rr->rd.len = ((0xff & P->data[p + 0]) << 8)
+ | ((0xff & P->data[p + 1]) << 0);
+ rr->rd.p = p + 2;
+
+ p += 2;
+
+ if (P->end - p < rr->rd.len)
+ goto invalid;
+
+ return 0;
+invalid:
+//assert(0);
+ return DNS_EILLEGAL;
+} /* dns_rr_parse() */
+
+
+static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
+ unsigned short rp, rdlen;
+
+ rp = dns_d_skip(src, P);
+
+ if (P->end - rp < 4)
+ return P->end - src;
+
+ rp += 4; /* TYPE, CLASS */
+
+ if (rp <= dns_p_qend(P))
+ return rp - src;
+
+ if (P->end - rp < 6)
+ return P->end - src;
+
+ rp += 6; /* TTL, RDLEN */
+
+ rdlen = ((0xff & P->data[rp - 2]) << 8)
+ | ((0xff & P->data[rp - 1]) << 0);
+
+ if (P->end - rp < rdlen)
+ return P->end - src;
+
+ rp += rdlen;
+
+ return rp - src;
+} /* dns_rr_len() */
+
+
+unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
+ return src + dns_rr_len(src, P);
+} /* dns_rr_skip() */
+
+
+static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
+ enum dns_section section;
+ unsigned count, ind;
+ unsigned short rp;
+
+ if (src >= P->qd.base && src < P->qd.end)
+ return DNS_S_QD;
+ if (src >= P->an.base && src < P->an.end)
+ return DNS_S_AN;
+ if (src >= P->ns.base && src < P->ns.end)
+ return DNS_S_NS;
+ if (src >= P->ar.base && src < P->ar.end)
+ return DNS_S_AR;
+
+ /* NOTE: Possibly bad memoization. Try it the hard-way. */
+
+ for (rp = 12, ind = 0; rp < src && rp < P->end; ind++)
+ rp = dns_rr_skip(rp, P);
+
+ section = DNS_S_QD;
+ count = dns_p_count(P, section);
+
+ while (ind >= count && section <= DNS_S_AR) {
+ section <<= 1;
+ count += dns_p_count(P, section);
+ }
+
+ return DNS_S_ALL & section;
+} /* dns_rr_section() */
+
+
+static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
+ struct dns_rr rr;
+ int error;
+
+ if ((error = dns_rr_parse(&rr, src, P)))
+ return 0;
+
+ return rr.type;
+} /* dns_rr_type() */
+
+
+int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
+ char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
+ union dns_any any0, any1;
+ int cmp, error;
+ size_t len;
+
+ if ((cmp = r0->type - r1->type))
+ return cmp;
+
+ if ((cmp = r0->class - r1->class))
+ return cmp;
+
+ /*
+ * FIXME: Do label-by-label comparison to handle illegally long names?
+ */
+
+ if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
+ || len >= sizeof host0)
+ return -1;
+
+ if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
+ || len >= sizeof host1)
+ return 1;
+
+ if ((cmp = strcasecmp(host0, host1)))
+ return cmp;
+
+ if (DNS_S_QD & (r0->section | r1->section)) {
+ if (r0->section == r1->section)
+ return 0;
+
+ return (r0->section == DNS_S_QD)? -1 : 1;
+ }
+
+ if ((error = dns_any_parse(&any0, r0, P0)))
+ return -1;
+
+ if ((error = dns_any_parse(&any1, r1, P1)))
+ return 1;
+
+ return dns_any_cmp(&any0, r0->type, &any1, r1->type);
+} /* dns_rr_cmp() */
+
+
+static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
+ struct dns_rr rr1;
+
+ dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
+ if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
+ return 1;
+ }
+
+ return 0;
+} /* dns_rr_exists() */
+
+
+static unsigned short dns_rr_offset(struct dns_rr *rr) {
+ return rr->dn.p;
+} /* dns_rr_offset() */
+
+
+static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
+ if (i->section && !(rr->section & i->section))
+ return 0;
+
+ if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
+ return 0;
+
+ if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
+ return 0;
+
+ if (i->name) {
+ char dn[DNS_D_MAXNAME + 1];
+ size_t len;
+ int error;
+
+ if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
+ || len >= sizeof dn)
+ return 0;
+
+ if (0 != strcasecmp(dn, i->name))
+ return 0;
+ }
+
+ if (i->data && i->type && rr->section > DNS_S_QD) {
+ union dns_any rd;
+ int error;
+
+ if ((error = dns_any_parse(&rd, rr, P)))
+ return 0;
+
+ if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
+ return 0;
+ }
+
+ return 1;
+} /* dns_rr_i_match() */
+
+
+static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
+ unsigned short rp;
+ struct dns_rr r0, rr;
+ int error;
+
+ if ((i->section & DNS_S_QD) && P->qd.base)
+ rp = P->qd.base;
+ else if ((i->section & DNS_S_AN) && P->an.base)
+ rp = P->an.base;
+ else if ((i->section & DNS_S_NS) && P->ns.base)
+ rp = P->ns.base;
+ else if ((i->section & DNS_S_AR) && P->ar.base)
+ rp = P->ar.base;
+ else
+ rp = 12;
+
+ for (rp = 12; rp < P->end; rp = dns_rr_skip(rp, P)) {
+ if ((error = dns_rr_parse(&rr, rp, P)))
+ continue;
+
+ rr.section = dns_rr_section(rp, P);
+
+ if (!dns_rr_i_match(&rr, i, P))
+ continue;
+
+ r0 = rr;
+
+ goto lower;
+ }
+
+ return P->end;
+lower:
+ if (i->sort == &dns_rr_i_packet)
+ return dns_rr_offset(&r0);
+
+ while ((rp = dns_rr_skip(rp, P)) < P->end) {
+ if ((error = dns_rr_parse(&rr, rp, P)))
+ continue;
+
+ rr.section = dns_rr_section(rp, P);
+
+ if (!dns_rr_i_match(&rr, i, P))
+ continue;
+
+ if (i->sort(&rr, &r0, i, P) < 0)
+ r0 = rr;
+ }
+
+ return dns_rr_offset(&r0);
+} /* dns_rr_i_start() */
+
+
+static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
+ struct dns_rr r0, r1, rr;
+ int error;
+
+ if ((error = dns_rr_parse(&r0, rp, P)))
+ return P->end;
+
+ r0.section = dns_rr_section(rp, P);
+
+ rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
+
+ for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
+ if ((error = dns_rr_parse(&rr, rp, P)))
+ continue;
+
+ rr.section = dns_rr_section(rp, P);
+
+ if (!dns_rr_i_match(&rr, i, P))
+ continue;
+
+ if (i->sort(&rr, &r0, i, P) <= 0)
+ continue;
+
+ r1 = rr;
+
+ goto lower;
+ }
+
+ return P->end;
+lower:
+ if (i->sort == &dns_rr_i_packet)
+ return dns_rr_offset(&r1);
+
+ while ((rp = dns_rr_skip(rp, P)) < P->end) {
+ if ((error = dns_rr_parse(&rr, rp, P)))
+ continue;
+
+ rr.section = dns_rr_section(rp, P);
+
+ if (!dns_rr_i_match(&rr, i, P))
+ continue;
+
+ if (i->sort(&rr, &r0, i, P) <= 0)
+ continue;
+
+ if (i->sort(&rr, &r1, i, P) >= 0)
+ continue;
+
+ r1 = rr;
+ }
+
+ return dns_rr_offset(&r1);
+} /* dns_rr_i_skip() */
+
+
+int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i EINA_UNUSED, struct dns_packet *P EINA_UNUSED) {
+ return (int)a->dn.p - (int)b->dn.p;
+} /* dns_rr_i_packet() */
+
+
+int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i EINA_UNUSED, struct dns_packet *P) {
+ int cmp;
+
+ if ((cmp = a->section - b->section))
+ return cmp;
+
+ if (a->type != b->type)
+ return (int)a->dn.p - (int)b->dn.p;
+
+ return dns_rr_cmp(a, P, b, P);
+} /* dns_rr_i_order() */
+
+
+int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P EINA_UNUSED) {
+ int cmp;
+
+ while (!i->state.regs[0])
+ i->state.regs[0] = dns_random();
+
+ if ((cmp = a->section - b->section))
+ return cmp;
+
+ return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
+} /* dns_rr_i_shuffle() */
+
+
+struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P EINA_UNUSED) {
+ static const struct dns_rr_i i_initializer;
+
+ i->state = i_initializer.state;
+ i->saved = i->state;
+
+ return i;
+} /* dns_rr_i_init() */
+
+
+unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
+ unsigned count = 0;
+ int error;
+
+ switch (i->state.exec) {
+ case 0:
+ if (!i->sort)
+ i->sort = &dns_rr_i_packet;
+
+ i->state.next = dns_rr_i_start(i, P);
+ i->state.exec++;
+
+ /* FALL THROUGH */
+ case 1:
+ while (count < lim && i->state.next < P->end) {
+ if ((error = dns_rr_parse(rr, i->state.next, P)))
+ goto error;
+
+ rr->section = dns_rr_section(i->state.next, P);
+
+ rr++;
+ count++;
+ i->state.count++;
+
+ i->state.next = dns_rr_i_skip(i->state.next, i, P);
+ } /* while() */
+
+ break;
+ } /* switch() */
+
+ return count;
+error:
+ *error_ = error;
+
+ return count;
+} /* dns_rr_grep() */
+
+
+static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) {
+ if (cp < lim)
+ ((unsigned char *)dst)[cp] = ch;
+
+ return 1;
+} /* dns__printchar() */
+
+
+static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) {
+ if (cp < lim)
+ memcpy(&((unsigned char *)dst)[cp], src, MIN(len, lim - cp));
+
+ return len;
+} /* dns__printstring() */
+
+#define dns__printstring5(a, b, c, d, e) dns__printstring((a), (b), (c), (d), (e))
+#define dns__printstring4(a, b, c, d) dns__printstring((a), (b), (c), (d), strlen((d)))
+#define dns__printstring(...) DNS_PP_CALL(DNS_PP_XPASTE(dns__printstring, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+
+static void dns__printnul(void *dst, size_t lim, size_t off) {
+ if (lim > 0)
+ ((unsigned char *)dst)[MIN(off, lim - 1)] = '\0';
+} /* dns__printnul() */
+
+
+static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) {
+ unsigned char tmp[32];
+ unsigned dp = off;
+ unsigned cp = 0;
+ unsigned d = 1000000000;
+ unsigned ch;
+
+ pad = MAX(1, pad);
+
+ while (d) {
+ if ((ch = n / d) || cp > 0) {
+ n -= ch * d;
+
+ tmp[cp] = '0' + ch;
+
+ cp++;
+ }
+
+ d /= 10;
+ }
+
+ while (cp < pad) {
+ dp += dns__printchar(dst, lim, dp, '0');
+ pad--;
+ }
+
+ dp += dns__printstring(dst, lim, dp, tmp, cp);
+
+ return dp - off;
+} /* dns__print10() */
+
+
+size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) {
+ union dns_any any;
+ size_t cp, n, rdlen;
+ void *rd;
+ int error;
+
+ cp = 0;
+
+ if (rr->section == DNS_S_QD)
+ cp += dns__printchar(dst, lim, cp, ';');
+
+ if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error)))
+ goto error;
+
+ cp += n;
+
+ if (rr->section != DNS_S_QD) {
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, rr->ttl, 0);
+ }
+
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__printstring(dst, lim, cp, dns_strclass(rr->class), strlen(dns_strclass(rr->class)));
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__printstring(dst, lim, cp, dns_strtype(rr->type), strlen(dns_strtype(rr->type)));
+
+ if (rr->section == DNS_S_QD)
+ goto epilog;
+
+ cp += dns__printchar(dst, lim, cp, ' ');
+
+ if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
+ goto error;
+
+ if (cp < lim) {
+ rd = &((unsigned char *)dst)[cp];
+ rdlen = lim - cp;
+ } else {
+ rd = 0;
+ rdlen = 0;
+ }
+
+ cp += dns_any_print(rd, rdlen, &any, rr->type);
+
+epilog:
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+error:
+ *error_ = error;
+
+ return 0;
+} /* dns_rr_print() */
+
+
+int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
+ unsigned long addr;
+
+ if (rr->rd.len != 4)
+ return DNS_EILLEGAL;
+
+ addr = ((0xff & P->data[rr->rd.p + 0]) << 24)
+ | ((0xff & P->data[rr->rd.p + 1]) << 16)
+ | ((0xff & P->data[rr->rd.p + 2]) << 8)
+ | ((0xff & P->data[rr->rd.p + 3]) << 0);
+
+ a->addr.s_addr = htonl(addr);
+
+ return 0;
+} /* dns_a_parse() */
+
+
+int dns_a_push(struct dns_packet *P, struct dns_a *a) {
+ unsigned long addr;
+
+ if (P->size - P->end < 6)
+ return DNS_ENOBUFS;
+
+ P->data[P->end++] = 0x00;
+ P->data[P->end++] = 0x04;
+
+ addr = ntohl(a->addr.s_addr);
+
+ P->data[P->end++] = 0xff & (addr >> 24);
+ P->data[P->end++] = 0xff & (addr >> 16);
+ P->data[P->end++] = 0xff & (addr >> 8);
+ P->data[P->end++] = 0xff & (addr >> 0);
+
+ return 0;
+} /* dns_a_push() */
+
+
+size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) {
+ unsigned long a4 = ntohl(a->addr.s_addr);
+ size_t cp = 0;
+ unsigned i;
+
+ for (i = 4; i > 0; i--) {
+ cp += dns__print10(dst, lim, cp, (0xff & a4), 0);
+ cp += dns__printchar(dst, lim, cp, '.');
+ a4 >>= 8;
+ }
+
+ cp += dns__printstring(dst, lim, cp, "in-addr.arpa.");
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_a_arpa() */
+
+
+int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
+ if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
+ return -1;
+ if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
+ return 1;
+
+ return 0;
+} /* dns_a_cmp() */
+
+
+size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
+ char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
+ size_t len;
+
+ dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
+
+ dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
+
+ return len;
+} /* dns_a_print() */
+
+
+int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
+ if (rr->rd.len != sizeof aaaa->addr.s6_addr)
+ return DNS_EILLEGAL;
+
+ memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
+
+ return 0;
+} /* dns_aaaa_parse() */
+
+
+int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
+ if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
+ return DNS_ENOBUFS;
+
+ P->data[P->end++] = 0x00;
+ P->data[P->end++] = 0x10;
+
+ memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
+
+ P->end += sizeof aaaa->addr.s6_addr;
+
+ return 0;
+} /* dns_aaaa_push() */
+
+
+int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
+ unsigned i;
+ int cmp;
+
+ for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
+ if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
+ return cmp;
+ }
+
+ return 0;
+} /* dns_aaaa_cmp() */
+
+
+size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) {
+ static const unsigned char hex[16] = "0123456789abcdef";
+ size_t cp = 0;
+ unsigned nyble;
+ int i, j;
+
+ for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
+ nyble = aaaa->addr.s6_addr[i];
+
+ for (j = 0; j < 2; j++) {
+ cp += dns__printchar(dst, lim, cp, hex[0x0f & nyble]);
+ cp += dns__printchar(dst, lim, cp, '.');
+ nyble >>= 4;
+ }
+ }
+
+ cp += dns__printstring(dst, lim, cp, "ip6.arpa.");
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_aaaa_arpa() */
+
+
+size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
+ char addr[INET6_ADDRSTRLEN + 1] = "::";
+ size_t len;
+
+ dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
+
+ dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr)));
+
+ return len;
+} /* dns_aaaa_print() */
+
+
+int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
+ size_t len;
+ int error;
+
+ if (rr->rd.len < 3)
+ return DNS_EILLEGAL;
+
+ mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
+ | (0x00ff & (P->data[rr->rd.p + 1] << 0));
+
+ if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
+ return error;
+ else if (len >= sizeof mx->host)
+ return DNS_EILLEGAL;
+
+ return 0;
+} /* dns_mx_parse() */
+
+
+int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
+ size_t end, len;
+ int error;
+
+ if (P->size - P->end < 5)
+ return DNS_ENOBUFS;
+
+ end = P->end;
+ P->end += 2;
+
+ P->data[P->end++] = 0xff & (mx->preference >> 8);
+ P->data[P->end++] = 0xff & (mx->preference >> 0);
+
+ if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
+ goto error;
+
+ len = P->end - end - 2;
+
+ P->data[end + 0] = 0xff & (len >> 8);
+ P->data[end + 1] = 0xff & (len >> 0);
+
+ return 0;
+error:
+ P->end = end;
+
+ return error;
+} /* dns_mx_push() */
+
+
+int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
+ int cmp;
+
+ if ((cmp = a->preference - b->preference))
+ return cmp;
+
+ return strcasecmp(a->host, b->host);
+} /* dns_mx_cmp() */
+
+
+size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) {
+ size_t cp = 0;
+
+ cp += dns__print10(dst, lim, cp, mx->preference, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host));
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_mx_print() */
+
+
+size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
+ return dns_strlcpy(dst, mx->host, lim);
+} /* dns_mx_cname() */
+
+
+int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
+ size_t len;
+ int error;
+
+ if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
+ return error;
+ else if (len >= sizeof ns->host)
+ return DNS_EILLEGAL;
+
+ return 0;
+} /* dns_ns_parse() */
+
+
+int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
+ size_t end, len;
+ int error;
+
+ if (P->size - P->end < 3)
+ return DNS_ENOBUFS;
+
+ end = P->end;
+ P->end += 2;
+
+ if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
+ goto error;
+
+ len = P->end - end - 2;
+
+ P->data[end + 0] = 0xff & (len >> 8);
+ P->data[end + 1] = 0xff & (len >> 0);
+
+ return 0;
+error:
+ P->end = end;
+
+ return error;
+} /* dns_ns_push() */
+
+
+int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
+ return strcasecmp(a->host, b->host);
+} /* dns_ns_cmp() */
+
+
+size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
+ size_t cp;
+
+ cp = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host));
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_ns_print() */
+
+
+size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
+ return dns_strlcpy(dst, ns->host, lim);
+} /* dns_ns_cname() */
+
+
+int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
+ return dns_ns_parse((struct dns_ns *)cname, rr, P);
+} /* dns_cname_parse() */
+
+
+int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
+ return dns_ns_push(P, (struct dns_ns *)cname);
+} /* dns_cname_push() */
+
+
+int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
+ return strcasecmp(a->host, b->host);
+} /* dns_cname_cmp() */
+
+
+size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
+ return dns_ns_print(dst, lim, (struct dns_ns *)cname);
+} /* dns_cname_print() */
+
+
+size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
+ return dns_strlcpy(dst, cname->host, lim);
+} /* dns_cname_cname() */
+
+
+int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
+ struct { void *dst; size_t lim; } dn[] =
+ { { soa->mname, sizeof soa->mname },
+ { soa->rname, sizeof soa->rname } };
+ unsigned *ts[] =
+ { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
+ unsigned short rp;
+ unsigned i, j, n;
+ int error;
+
+ /* MNAME / RNAME */
+ if ((rp = rr->rd.p) >= P->end)
+ return DNS_EILLEGAL;
+
+ for (i = 0; i < lengthof(dn); i++) {
+ if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
+ return error;
+ else if (n >= dn[i].lim)
+ return DNS_EILLEGAL;
+
+ if ((rp = dns_d_skip(rp, P)) >= P->end)
+ return DNS_EILLEGAL;
+ }
+
+ /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
+ for (i = 0; i < lengthof(ts); i++) {
+ for (j = 0; j < 4; j++, rp++) {
+ if (rp >= P->end)
+ return DNS_EILLEGAL;
+
+ *ts[i] <<= 8;
+ *ts[i] |= (0xff & P->data[rp]);
+ }
+ }
+
+ return 0;
+} /* dns_soa_parse() */
+
+
+int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
+ void *dn[] = { soa->mname, soa->rname };
+ unsigned ts[] = { (0xffffffff & soa->serial),
+ (0x7fffffff & soa->refresh),
+ (0x7fffffff & soa->retry),
+ (0x7fffffff & soa->expire),
+ (0xffffffff & soa->minimum) };
+ unsigned i, j;
+ size_t end, len;
+ int error;
+
+ end = P->end;
+
+ if ((P->end += 2) >= P->size)
+ goto toolong;
+
+ /* MNAME / RNAME */
+ for (i = 0; i < lengthof(dn); i++) {
+ if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
+ goto error;
+ }
+
+ /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
+ for (i = 0; i < lengthof(ts); i++) {
+ if ((P->end += 4) >= P->size)
+ goto toolong;
+
+ for (j = 1; j <= 4; j++) {
+ P->data[P->end - j] = (0xff & ts[i]);
+ ts[i] >>= 8;
+ }
+ }
+
+ len = P->end - end - 2;
+ P->data[end + 0] = (0xff & (len >> 8));
+ P->data[end + 1] = (0xff & (len >> 0));
+
+ return 0;
+toolong:
+ error = DNS_ENOBUFS;
+
+ /* FALL THROUGH */
+error:
+ P->end = end;
+
+ return error;
+} /* dns_soa_push() */
+
+
+int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
+ int cmp;
+
+ if ((cmp = strcasecmp(a->mname, b->mname)))
+ return cmp;
+
+ if ((cmp = strcasecmp(a->rname, b->rname)))
+ return cmp;
+
+ if (a->serial > b->serial)
+ return -1;
+ else if (a->serial < b->serial)
+ return 1;
+
+ if (a->refresh > b->refresh)
+ return -1;
+ else if (a->refresh < b->refresh)
+ return 1;
+
+ if (a->retry > b->retry)
+ return -1;
+ else if (a->retry < b->retry)
+ return 1;
+
+ if (a->expire > b->expire)
+ return -1;
+ else if (a->expire < b->expire)
+ return 1;
+
+ if (a->minimum > b->minimum)
+ return -1;
+ else if (a->minimum < b->minimum)
+ return 1;
+
+ return 0;
+} /* dns_soa_cmp() */
+
+
+size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) {
+ size_t cp = 0;
+
+ cp += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname));
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname));
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, soa->serial, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, soa->refresh, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, soa->retry, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, soa->expire, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, soa->minimum, 0);
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_soa_print() */
+
+
+int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
+ unsigned short rp;
+ unsigned i;
+ size_t n;
+ int error;
+
+ memset(srv, '\0', sizeof *srv);
+
+ rp = rr->rd.p;
+
+ if (P->size - P->end < 6)
+ return DNS_EILLEGAL;
+
+ for (i = 0; i < 2; i++, rp++) {
+ srv->priority <<= 8;
+ srv->priority |= (0xff & P->data[rp]);
+ }
+
+ for (i = 0; i < 2; i++, rp++) {
+ srv->weight <<= 8;
+ srv->weight |= (0xff & P->data[rp]);
+ }
+
+ for (i = 0; i < 2; i++, rp++) {
+ srv->port <<= 8;
+ srv->port |= (0xff & P->data[rp]);
+ }
+
+ if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
+ return error;
+ else if (n >= sizeof srv->target)
+ return DNS_EILLEGAL;
+
+ return 0;
+} /* dns_srv_parse() */
+
+
+int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
+ size_t end, len;
+ int error;
+
+ end = P->end;
+
+ if (P->size - P->end < 2)
+ goto toolong;
+
+ P->end += 2;
+
+ if (P->size - P->end < 6)
+ goto toolong;
+
+ P->data[P->end++] = 0xff & (srv->priority >> 8);
+ P->data[P->end++] = 0xff & (srv->priority >> 0);
+
+ P->data[P->end++] = 0xff & (srv->weight >> 8);
+ P->data[P->end++] = 0xff & (srv->weight >> 0);
+
+ P->data[P->end++] = 0xff & (srv->port >> 8);
+ P->data[P->end++] = 0xff & (srv->port >> 0);
+
+ if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
+ goto error;
+ else if (P->size - P->end < len)
+ goto toolong;
+
+ P->end += len;
+
+ if (P->end > 65535)
+ goto toolong;
+
+ len = P->end - end - 2;
+
+ P->data[end + 0] = 0xff & (len >> 8);
+ P->data[end + 1] = 0xff & (len >> 0);
+
+ return 0;
+toolong:
+ error = DNS_ENOBUFS;
+
+ /* FALL THROUGH */
+error:
+ P->end = end;
+
+ return error;
+} /* dns_srv_push() */
+
+
+int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
+ int cmp;
+
+ if ((cmp = a->priority - b->priority))
+ return cmp;
+
+ /*
+ * FIXME: We need some sort of random seed to implement the dynamic
+ * weighting required by RFC 2782.
+ */
+ if ((cmp = a->weight - b->weight))
+ return cmp;
+
+ if ((cmp = a->port - b->port))
+ return cmp;
+
+ return strcasecmp(a->target, b->target);
+} /* dns_srv_cmp() */
+
+
+size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) {
+ size_t cp = 0;
+
+ cp += dns__print10(dst, lim, cp, srv->priority, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, srv->weight, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__print10(dst, lim, cp, srv->port, 0);
+ cp += dns__printchar(dst, lim, cp, ' ');
+ cp += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target));
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_srv_print() */
+
+
+size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
+ return dns_strlcpy(dst, srv->target, lim);
+} /* dns_srv_cname() */
+
+
+int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
+ return dns_ns_parse((struct dns_ns *)ptr, rr, P);
+} /* dns_ptr_parse() */
+
+
+int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
+ return dns_ns_push(P, (struct dns_ns *)ptr);
+} /* dns_ptr_push() */
+
+
+size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
+ unsigned len = (af == AF_INET6)
+ ? dns_aaaa_arpa(dst, lim, addr)
+ : dns_a_arpa(dst, lim, addr);
+
+ dns__printnul(dst, lim, len);
+
+ return len;
+} /* dns_ptr_qname() */
+
+
+int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
+ return strcasecmp(a->host, b->host);
+} /* dns_ptr_cmp() */
+
+
+size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
+ return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
+} /* dns_ptr_print() */
+
+
+size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
+ return dns_strlcpy(dst, ptr->host, lim);
+} /* dns_ptr_cname() */
+
+
+int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
+ unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
+
+ if (pe - p < 2)
+ return DNS_EILLEGAL;
+
+ fp->algo = P->data[p++];
+ fp->type = P->data[p++];
+
+ switch (fp->type) {
+ case DNS_SSHFP_SHA1:
+ if (pe - p < sizeof fp->digest.sha1)
+ return DNS_EILLEGAL;
+
+ memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
+
+ break;
+ default:
+ break;
+ } /* switch() */
+
+ return 0;
+} /* dns_sshfp_parse() */
+
+
+int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
+ unsigned p = P->end, pe = P->size, n;
+
+ if (pe - p < 4)
+ return DNS_ENOBUFS;
+
+ p += 2;
+ P->data[p++] = 0xff & fp->algo;
+ P->data[p++] = 0xff & fp->type;
+
+ switch (fp->type) {
+ case DNS_SSHFP_SHA1:
+ if (pe - p < sizeof fp->digest.sha1)
+ return DNS_ENOBUFS;
+
+ memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
+ p += sizeof fp->digest.sha1;
+
+ break;
+ default:
+ return DNS_EILLEGAL;
+ } /* switch() */
+
+ n = p - P->end - 2;
+ P->data[P->end++] = 0xff & (n >> 8);
+ P->data[P->end++] = 0xff & (n >> 0);
+ P->end = p;
+
+ return 0;
+} /* dns_sshfp_push() */
+
+
+int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
+ int cmp;
+
+ if ((cmp = a->algo - b->algo) || (cmp - a->type - b->type))
+ return cmp;
+
+ switch (a->type) {
+ case DNS_SSHFP_SHA1:
+ return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
+ default:
+ return 0;
+ } /* switch() */
+
+ /* NOT REACHED */
+} /* dns_sshfp_cmp() */
+
+
+size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) {
+ static const unsigned char hex[16] = "0123456789abcdef";
+ size_t i, p = 0;
+
+ p += dns__print10(dst, lim, p, fp->algo, 0);
+ p += dns__printchar(dst, lim, p, ' ');
+ p += dns__print10(dst, lim, p, fp->type, 0);
+ p += dns__printchar(dst, lim, p, ' ');
+
+ switch (fp->type) {
+ case DNS_SSHFP_SHA1:
+ for (i = 0; i < sizeof fp->digest.sha1; i++) {
+ p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
+ p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
+ }
+
+ break;
+ default:
+ p += dns__printchar(dst, lim, p, '0');
+
+ break;
+ } /* switch() */
+
+ dns__printnul(dst, lim, p);
+
+ return p;
+} /* dns_sshfp_print() */
+
+
+struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
+ assert(size > offsetof(struct dns_txt, data));
+
+ txt->size = size - offsetof(struct dns_txt, data);
+ txt->len = 0;
+
+ return txt;
+} /* dns_txt_init() */
+
+
+int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
+ struct { unsigned char *b; size_t p, end; } dst, src;
+ unsigned n;
+
+ dst.b = txt->data;
+ dst.p = 0;
+ dst.end = txt->size;
+
+ src.b = P->data;
+ src.p = rr->rd.p;
+ src.end = src.p + rr->rd.len;
+
+ while (src.p < src.end) {
+ n = 0xff & P->data[src.p++];
+
+ if (src.end - src.p < n || dst.end - dst.p < n)
+ return DNS_EILLEGAL;
+
+ memcpy(&dst.b[dst.p], &src.b[src.p], n);
+
+ dst.p += n;
+ src.p += n;
+ }
+
+ txt->len = dst.p;
+
+ return 0;
+} /* dns_txt_parse() */
+
+
+int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
+ struct { unsigned char *b; size_t p, end; } dst, src;
+ unsigned n;
+
+ dst.b = P->data;
+ dst.p = P->end;
+ dst.end = P->size;
+
+ src.b = txt->data;
+ src.p = 0;
+ src.end = txt->len;
+
+ if (dst.end - dst.p < 2)
+ return DNS_ENOBUFS;
+
+ n = txt->len + ((txt->len + 254) / 255);
+
+ dst.b[dst.p++] = 0xff & (n >> 8);
+ dst.b[dst.p++] = 0xff & (n >> 0);
+
+ while (src.p < src.end) {
+ n = MIN(255, src.end - src.p);
+
+ if (dst.p >= dst.end)
+ return DNS_ENOBUFS;
+
+ dst.b[dst.p++] = n;
+
+ if (dst.end - dst.p < n)
+ return DNS_ENOBUFS;
+
+ memcpy(&dst.b[dst.p], &src.b[src.p], n);
+
+ dst.p += n;
+ src.p += n;
+ }
+
+ P->end = dst.p;
+
+ return 0;
+} /* dns_txt_push() */
+
+
+int dns_txt_cmp(const struct dns_txt *a EINA_UNUSED, const struct dns_txt *b EINA_UNUSED) {
+ return -1;
+} /* dns_txt_cmp() */
+
+
+size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) {
+ struct { unsigned char *b; size_t p, end; } dst, src;
+ unsigned ch;
+
+ dst.b = dst_;
+ dst.end = lim;
+ dst.p = 0;
+
+ src.b = txt->data;
+ src.end = txt->len;
+ src.p = 0;
+
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+
+ while (src.p < src.end) {
+ ch = src.b[src.p];
+
+ if (0 == (src.p++ % 255) && src.p != 1) {
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, ' ');
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+ }
+
+ if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') {
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\');
+ dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3);
+ } else {
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, ch);
+ }
+ }
+
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+
+ dns__printnul(dst.b, dst.end, dst.p);
+
+ return dst.p;
+} /* dns_txt_print() */
+
+
+static const struct {
+ enum dns_type type;
+ const char *name;
+ int (*parse)();
+ int (*push)();
+ int (*cmp)();
+ size_t (*print)();
+ size_t (*cname)();
+} dns_rrtypes[] = {
+ { DNS_T_A, "A", &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0 },
+ { DNS_T_AAAA, "AAAA", &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0 },
+ { DNS_T_MX, "MX", &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname },
+ { DNS_T_NS, "NS", &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname },
+ { DNS_T_CNAME, "CNAME", &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname },
+ { DNS_T_SOA, "SOA", &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0 },
+ { DNS_T_SRV, "SRV", &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname },
+ { DNS_T_PTR, "PTR", &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname },
+ { DNS_T_TXT, "TXT", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 },
+ { DNS_T_SPF, "SPF", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 },
+ { DNS_T_SSHFP, "SSHFP", &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0 },
+}; /* dns_rrtypes[] */
+
+
+union dns_any *dns_any_init(union dns_any *any, size_t size) {
+ return (union dns_any *)dns_txt_init(&any->rdata, size);
+} /* dns_any_init() */
+
+
+int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == rr->type)
+ return dns_rrtypes[i].parse(any, rr, P);
+ }
+
+ if (rr->rd.len > any->rdata.size)
+ return DNS_EILLEGAL;
+
+ memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
+ any->rdata.len = rr->rd.len;
+
+ return 0;
+} /* dns_any_parse() */
+
+
+int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == type)
+ return dns_rrtypes[i].push(P, any);
+ }
+
+ if (P->size - P->end < any->rdata.len + 2)
+ return DNS_ENOBUFS;
+
+ P->data[P->end++] = 0xff & (any->rdata.len >> 8);
+ P->data[P->end++] = 0xff & (any->rdata.len >> 0);
+
+ memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
+ P->end += any->rdata.len;
+
+ return 0;
+} /* dns_any_push() */
+
+
+int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
+ unsigned i;
+ int cmp;
+
+ if ((cmp = x - y))
+ return cmp;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == x)
+ return dns_rrtypes[i].cmp(a, b);
+ }
+
+ return -1;
+} /* dns_any_cmp() */
+
+
+size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) {
+ struct { unsigned char *b; size_t p, end; } dst, src;
+ unsigned i, ch;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == type)
+ return dns_rrtypes[i].print(dst_, lim, any);
+ }
+
+ dst.b = dst_;
+ dst.end = lim;
+ dst.p = 0;
+
+ src.b = any->rdata.data;
+ src.end = any->rdata.len;
+ src.p = 0;
+
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+
+ while (src.p < src.end) {
+ ch = src.b[src.p++];
+
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\');
+ dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3);
+ }
+
+ dst.p += dns__printchar(dst.b, dst.end, dst.p, '"');
+
+ dns__printnul(dst.b, dst.end, dst.p);
+
+ return dst.p;
+} /* dns_any_print() */
+
+
+size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == type)
+ return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0;
+ }
+
+ return 0;
+} /* dns_any_cname() */
+
+
+/*
+ * H O S T S R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_hosts {
+ struct dns_hosts_entry {
+ char host[DNS_D_MAXNAME + 1];
+ char arpa[73 + 1];
+
+ int af;
+
+ union {
+ struct in_addr a4;
+ struct in6_addr a6;
+ } addr;
+
+ _Bool alias;
+
+ struct dns_hosts_entry *next;
+ } *head, **tail;
+
+ dns_atomic_t refcount;
+}; /* struct dns_hosts */
+
+
+struct dns_hosts *dns_hosts_open(int *error) {
+ static const struct dns_hosts hosts_initializer = { .refcount = 1 };
+ struct dns_hosts *hosts;
+
+ if (!(hosts = malloc(sizeof *hosts)))
+ goto syerr;
+
+ *hosts = hosts_initializer;
+
+ hosts->tail = &hosts->head;
+
+ return hosts;
+syerr:
+ *error = dns_syerr();
+
+ free(hosts);
+
+ return 0;
+} /* dns_hosts_open() */
+
+
+void dns_hosts_close(struct dns_hosts *hosts) {
+ struct dns_hosts_entry *ent, *xnt;
+
+ if (!hosts || 1 != dns_hosts_release(hosts))
+ return;
+
+ for (ent = hosts->head; ent; ent = xnt) {
+ xnt = ent->next;
+
+ free(ent);
+ }
+
+ free(hosts);
+
+ return;
+} /* dns_hosts_close() */
+
+
+unsigned dns_hosts_acquire(struct dns_hosts *hosts) {
+ return dns_atomic_inc(&hosts->refcount);
+} /* dns_hosts_acquire() */
+
+
+unsigned dns_hosts_release(struct dns_hosts *hosts) {
+ return dns_atomic_dec(&hosts->refcount);
+} /* dns_hosts_release() */
+
+
+struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
+ if (hosts)
+ dns_hosts_release(hosts);
+
+ return hosts;
+} /* dns_hosts_mortal() */
+
+
+struct dns_hosts *dns_hosts_local(int *error_) {
+ struct dns_hosts *hosts;
+ int error;
+
+ if (!(hosts = dns_hosts_open(&error)))
+ goto error;
+
+ if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
+ goto error;
+
+ return hosts;
+error:
+ *error_ = error;
+
+ dns_hosts_close(hosts);
+
+ return 0;
+} /* dns_hosts_local() */
+
+
+#define dns_hosts_issep(ch) (isspace(ch))
+#define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
+
+int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
+ struct dns_hosts_entry ent;
+ char word[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
+ unsigned wp, wc, skip;
+ int ch, error;
+
+ rewind(fp);
+
+ do {
+ memset(&ent, '\0', sizeof ent);
+ wc = 0;
+ skip = 0;
+
+ do {
+ memset(word, '\0', sizeof word);
+ wp = 0;
+
+ while (EOF != (ch = fgetc(fp)) && ch != '\n') {
+ skip |= !!dns_hosts_iscom(ch);
+
+ if (skip)
+ continue;
+
+ if (dns_hosts_issep(ch))
+ break;
+
+ if (wp < sizeof word - 1)
+ word[wp] = ch;
+ wp++;
+ }
+
+ if (!wp)
+ continue;
+
+ wc++;
+
+ switch (wc) {
+ case 0:
+ break;
+ case 1:
+ ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
+ skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
+
+ break;
+ default:
+ if (!wp)
+ break;
+
+ dns_d_anchor(ent.host, sizeof ent.host, word, wp);
+
+ if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
+ return error;
+
+ break;
+ } /* switch() */
+ } while (ch != EOF && ch != '\n');
+ } while (ch != EOF);
+
+ return 0;
+} /* dns_hosts_loadfile() */
+
+
+int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
+ FILE *fp;
+ int error;
+
+ if (!(fp = fopen(path, "r")))
+ return dns_syerr();
+
+ error = dns_hosts_loadfile(hosts, fp);
+
+ fclose(fp);
+
+ return error;
+} /* dns_hosts_loadpath() */
+
+
+int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
+ struct dns_hosts_entry *ent, *xnt;
+ char addr[INET6_ADDRSTRLEN + 1];
+ unsigned i;
+
+ for (ent = hosts->head; ent; ent = xnt) {
+ xnt = ent->next;
+
+ dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
+
+ fputs(addr, fp);
+
+ for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
+ fputc(' ', fp);
+
+ fputc(' ', fp);
+
+ fputs(ent->host, fp);
+ fputc('\n', fp);
+ }
+
+ return 0;
+} /* dns_hosts_dump() */
+
+
+int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
+ struct dns_hosts_entry *ent;
+ int error;
+
+ if (!(ent = malloc(sizeof *ent)))
+ goto syerr;
+
+ dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
+
+ switch ((ent->af = af)) {
+ case AF_INET6:
+ memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
+
+ dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
+
+ break;
+ case AF_INET:
+ memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
+
+ dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
+
+ break;
+ default:
+ error = EINVAL;
+
+ goto error;
+ } /* switch() */
+
+ ent->alias = alias;
+
+ ent->next = 0;
+ *hosts->tail = ent;
+ hosts->tail = &ent->next;
+
+ return 0;
+syerr:
+ error = dns_syerr();
+error:
+ free(ent);
+
+ return error;
+} /* dns_hosts_insert() */
+
+
+struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
+ struct dns_packet *P = dns_p_new(512);
+ struct dns_packet *A = 0;
+ struct dns_rr rr;
+ struct dns_hosts_entry *ent;
+ int error, af;
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+
+ if ((error = dns_rr_parse(&rr, 12, Q)))
+ goto error;
+
+ if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
+ goto error;
+ else if (qlen >= sizeof qname)
+ goto toolong;
+
+ if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
+ goto error;
+
+ switch (rr.type) {
+ case DNS_T_PTR:
+ for (ent = hosts->head; ent; ent = ent->next) {
+ if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
+ continue;
+
+ if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
+ goto error;
+ }
+
+ break;
+ case DNS_T_AAAA:
+ af = AF_INET6;
+
+ goto loop;
+ case DNS_T_A:
+ af = AF_INET;
+
+loop: for (ent = hosts->head; ent; ent = ent->next) {
+ if (ent->af != af || 0 != strcasecmp(qname, ent->host))
+ continue;
+
+ if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
+ goto error;
+ }
+
+ break;
+ default:
+ break;
+ } /* switch() */
+
+
+ if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
+ goto error;
+
+ return A;
+toolong:
+ error = DNS_EILLEGAL;
+error:
+ *error_ = error;
+
+ free(A);
+
+ return 0;
+} /* dns_hosts_query() */
+
+
+/*
+ * R E S O L V . C O N F R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_resolv_conf *dns_resconf_open(int *error) {
+ static const struct dns_resolv_conf resconf_initializer
+ = { .lookup = "bf", .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
+ .iface = { .ss_family = AF_INET }, };
+ struct dns_resolv_conf *resconf;
+ struct sockaddr_in *sin;
+
+ if (!(resconf = malloc(sizeof *resconf)))
+ goto syerr;
+
+ *resconf = resconf_initializer;
+
+ sin = (struct sockaddr_in *)&resconf->nameserver[0];
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = htons(53);
+#if defined(SA_LEN)
+ sin->sin_len = sizeof *sin;
+#endif
+
+ if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
+ goto syerr;
+
+ dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
+ dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
+
+ /*
+ * XXX: If gethostname() returned a string without any label
+ * separator, then search[0][0] should be NUL.
+ */
+
+ dns_resconf_acquire(resconf);
+
+ return resconf;
+syerr:
+ *error = dns_syerr();
+
+ free(resconf);
+
+ return 0;
+} /* dns_resconf_open() */
+
+
+void dns_resconf_close(struct dns_resolv_conf *resconf) {
+ if (!resconf || 1 != dns_resconf_release(resconf))
+ return /* void */;
+
+ free(resconf);
+} /* dns_resconf_close() */
+
+
+unsigned dns_resconf_acquire(struct dns_resolv_conf *resconf) {
+ return dns_atomic_inc(&resconf->_.refcount);
+} /* dns_resconf_acquire() */
+
+
+unsigned dns_resconf_release(struct dns_resolv_conf *resconf) {
+ return dns_atomic_dec(&resconf->_.refcount);
+} /* dns_resconf_release() */
+
+
+struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
+ if (resconf)
+ dns_resconf_release(resconf);
+
+ return resconf;
+} /* dns_resconf_mortal() */
+
+
+struct dns_resolv_conf *dns_resconf_local(int *error_) {
+ struct dns_resolv_conf *resconf;
+ int error;
+
+ if (!(resconf = dns_resconf_open(&error)))
+ goto error;
+
+ if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf")))
+ goto error;
+
+ return resconf;
+error:
+ *error_ = error;
+
+ dns_resconf_close(resconf);
+
+ return 0;
+} /* dns_resconf_local() */
+
+
+struct dns_resolv_conf *dns_resconf_root(int *error_) {
+ struct dns_resolv_conf *resconf;
+ int error;
+
+ if (!(resconf = dns_resconf_open(&error)))
+ goto error;
+
+ if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf")))
+ goto error;
+
+ resconf->options.recurse = 1;
+
+ return resconf;
+error:
+ *error_ = error;
+
+ dns_resconf_close(resconf);
+
+ return 0;
+} /* dns_resconf_root() */
+
+
+enum dns_resconf_keyword {
+ DNS_RESCONF_NAMESERVER,
+ DNS_RESCONF_DOMAIN,
+ DNS_RESCONF_SEARCH,
+ DNS_RESCONF_LOOKUP,
+ DNS_RESCONF_FILE,
+ DNS_RESCONF_BIND,
+ DNS_RESCONF_CACHE,
+ DNS_RESCONF_OPTIONS,
+ DNS_RESCONF_EDNS0,
+ DNS_RESCONF_NDOTS,
+ DNS_RESCONF_TIMEOUT,
+ DNS_RESCONF_ATTEMPTS,
+ DNS_RESCONF_ROTATE,
+ DNS_RESCONF_RECURSE,
+ DNS_RESCONF_SMART,
+ DNS_RESCONF_TCP,
+ DNS_RESCONF_TCPx,
+ DNS_RESCONF_INTERFACE,
+ DNS_RESCONF_ZERO,
+ DNS_RESCONF_ONE,
+ DNS_RESCONF_ENABLE,
+ DNS_RESCONF_ONLY,
+ DNS_RESCONF_DISABLE,
+}; /* enum dns_resconf_keyword */
+
+static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
+ static const char *words[] = {
+ [DNS_RESCONF_NAMESERVER] = "nameserver",
+ [DNS_RESCONF_DOMAIN] = "domain",
+ [DNS_RESCONF_SEARCH] = "search",
+ [DNS_RESCONF_LOOKUP] = "lookup",
+ [DNS_RESCONF_FILE] = "file",
+ [DNS_RESCONF_BIND] = "bind",
+ [DNS_RESCONF_CACHE] = "cache",
+ [DNS_RESCONF_OPTIONS] = "options",
+ [DNS_RESCONF_EDNS0] = "edns0",
+ [DNS_RESCONF_ROTATE] = "rotate",
+ [DNS_RESCONF_RECURSE] = "recurse",
+ [DNS_RESCONF_SMART] = "smart",
+ [DNS_RESCONF_TCP] = "tcp",
+ [DNS_RESCONF_INTERFACE] = "interface",
+ [DNS_RESCONF_ZERO] = "0",
+ [DNS_RESCONF_ONE] = "1",
+ [DNS_RESCONF_ENABLE] = "enable",
+ [DNS_RESCONF_ONLY] = "only",
+ [DNS_RESCONF_DISABLE] = "disable",
+ };
+ unsigned i;
+
+ for (i = 0; i < lengthof(words); i++) {
+ if (words[i] && 0 == strcasecmp(words[i], word))
+ return i;
+ }
+
+ if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
+ return DNS_RESCONF_NDOTS;
+
+ if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
+ return DNS_RESCONF_TIMEOUT;
+
+ if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
+ return DNS_RESCONF_ATTEMPTS;
+
+ if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
+ return DNS_RESCONF_TCPx;
+
+ return -1;
+} /* dns_resconf_keyword() */
+
+
+/** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
+static int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
+ struct { char buf[128], *p; } addr = { "", addr.buf };
+ unsigned short port = 0;
+ int ch, af = AF_INET;
+
+ while ((ch = *src++)) {
+ switch (ch) {
+ case ' ':
+ /* FALL THROUGH */
+ case '\t':
+ break;
+ case '[':
+ break;
+ case ']':
+ while ((ch = *src++)) {
+ if (isdigit((unsigned char)ch)) {
+ port *= 10;
+ port += ch - '0';
+ }
+ }
+
+ goto inet;
+ case ':':
+ af = AF_INET6;
+
+ /* FALL THROUGH */
+ default:
+ if (addr.p < endof(addr.buf) - 1)
+ *addr.p++ = ch;
+
+ break;
+ } /* switch() */
+ } /* while() */
+inet:
+
+ switch (dns_inet_pton(af, addr.buf, dns_sa_addr(af, ss))) {
+ case -1:
+ return errno;
+ case 0:
+ return EINVAL;
+ } /* switch() */
+
+ port = (!port)? 53 : port;
+ *dns_sa_port(af, ss) = htons(port);
+ dns_sa_family(ss) = af;
+
+ return 0;
+} /* dns_resconf_pton() */
+
+#define dns_resconf_issep(ch) (isspace(ch) || (ch) == ',')
+#define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
+
+int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
+ unsigned sa_count = 0;
+ char words[6][DNS_D_MAXNAME + 1];
+ unsigned wp, wc, i, j, n;
+ int ch, error;
+
+ rewind(fp);
+
+ do {
+ memset(words, '\0', sizeof words);
+ wp = 0;
+ wc = 0;
+
+ while (EOF != (ch = getc(fp)) && ch != '\n') {
+ if (dns_resconf_issep(ch)) {
+ if (wp > 0) {
+ wp = 0;
+
+ if (++wc >= lengthof(words))
+ goto skip;
+ }
+ } else if (dns_resconf_iscom(ch)) {
+skip:
+ do {
+ ch = getc(fp);
+ } while (ch != EOF && ch != '\n');
+
+ break;
+ } else {
+ dns__printchar(words[wc], sizeof words[wc], wp, ch);
+ wp++;
+ }
+ }
+
+ if (wp > 0)
+ wc++;
+
+ if (wc < 2)
+ continue;
+
+ switch (dns_resconf_keyword(words[0])) {
+ case DNS_RESCONF_NAMESERVER:
+ if (sa_count >= lengthof(resconf->nameserver))
+ continue;
+
+ if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
+ continue;
+
+ sa_count++;
+
+ break;
+ case DNS_RESCONF_DOMAIN:
+ case DNS_RESCONF_SEARCH:
+ memset(resconf->search, '\0', sizeof resconf->search);
+
+ for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
+ dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
+
+ break;
+ case DNS_RESCONF_LOOKUP:
+ for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
+ switch (dns_resconf_keyword(words[i])) {
+ case DNS_RESCONF_FILE:
+ resconf->lookup[j++] = 'f';
+
+ break;
+ case DNS_RESCONF_BIND:
+ resconf->lookup[j++] = 'b';
+
+ break;
+ case DNS_RESCONF_CACHE:
+ resconf->lookup[j++] = 'c';
+
+ break;
+ default:
+ break;
+ } /* switch() */
+ } /* for() */
+
+ break;
+ case DNS_RESCONF_OPTIONS:
+ for (i = 1; i < wc; i++) {
+ switch (dns_resconf_keyword(words[i])) {
+ case DNS_RESCONF_EDNS0:
+ resconf->options.edns0 = 1;
+
+ break;
+ case DNS_RESCONF_NDOTS:
+ for (j = sizeof "ndots:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
+ n *= 10;
+ n += words[i][j] - '0';
+ } /* for() */
+
+ resconf->options.ndots = n;
+
+ break;
+ case DNS_RESCONF_TIMEOUT:
+ for (j = sizeof "timeout:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
+ n *= 10;
+ n += words[i][j] - '0';
+ } /* for() */
+
+ resconf->options.timeout = n;
+
+ break;
+ case DNS_RESCONF_ATTEMPTS:
+ for (j = sizeof "attempts:" - 1, n = 0; isdigit((int)words[i][j]); j++) {
+ n *= 10;
+ n += words[i][j] - '0';
+ } /* for() */
+
+ resconf->options.attempts = n;
+
+ break;
+ case DNS_RESCONF_ROTATE:
+ resconf->options.rotate = 1;
+
+ break;
+ case DNS_RESCONF_RECURSE:
+ resconf->options.recurse = 1;
+
+ break;
+ case DNS_RESCONF_SMART:
+ resconf->options.smart = 1;
+
+ break;
+ case DNS_RESCONF_TCP:
+ resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
+
+ break;
+ case DNS_RESCONF_TCPx:
+ switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
+ case DNS_RESCONF_ENABLE:
+ resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
+
+ break;
+ case DNS_RESCONF_ONE:
+ case DNS_RESCONF_ONLY:
+ resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
+
+ break;
+ case DNS_RESCONF_ZERO:
+ case DNS_RESCONF_DISABLE:
+ resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
+
+ break;
+ default:
+ break;
+ } /* switch() */
+
+ break;
+ default:
+ break;
+ } /* switch() */
+ } /* for() */
+
+ break;
+ case DNS_RESCONF_INTERFACE:
+ for (i = 0, n = 0; isdigit((int)words[2][i]); i++) {
+ n *= 10;
+ n += words[2][i] - '0';
+ }
+
+ dns_resconf_setiface(resconf, words[1], n);
+
+ break;
+ default:
+ break;
+ } /* switch() */
+ } while (ch != EOF);
+
+ return 0;
+} /* dns_resconf_loadfile() */
+
+
+int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
+ FILE *fp;
+ int error;
+
+ if (!(fp = fopen(path, "r")))
+ return dns_syerr();
+
+ error = dns_resconf_loadfile(resconf, fp);
+
+ fclose(fp);
+
+ return error;
+} /* dns_resconf_loadpath() */
+
+
+int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
+ int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
+
+ if (1 != dns_inet_pton(af, addr, dns_sa_addr(af, &resconf->iface)))
+ return dns_soerr();
+
+ *dns_sa_port(af, &resconf->iface) = htons(port);
+ resconf->iface.ss_family = af;
+
+ return 0;
+} /* dns_resconf_setiface() */
+
+
+size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) {
+ unsigned srchi = 0xff & (*state >> 8);
+ unsigned ndots = 0xff & (*state >> 16);
+ unsigned slen, len = 0;
+ const char *qp, *qe;
+
+// assert(0xff > lengthof(resconf->search));
+
+ switch (0xff & *state) {
+ case 0:
+ qp = qname;
+ qe = qp + qlen;
+
+ while ((qp = memchr(qp, '.', qe - qp)))
+ { ndots++; qp++; }
+
+ ++*state;
+
+ if (ndots >= resconf->options.ndots) {
+ len = dns_d_anchor(dst, lim, qname, qlen);
+
+ break;
+ }
+
+ /* FALL THROUGH */
+ case 1:
+ if (srchi < lengthof(resconf->search) && (slen = strlen(resconf->search[srchi]))) {
+ len = dns__printstring(dst, lim, 0, qname, qlen);
+ len = dns_d_anchor(dst, lim, dst, len);
+ len += dns__printstring(dst, lim, len, resconf->search[srchi], slen);
+
+ srchi++;
+
+ break;
+ }
+
+ ++*state;
+
+ /* FALL THROUGH */
+ case 2:
+ ++*state;
+
+ if (ndots < resconf->options.ndots) {
+ len = dns_d_anchor(dst, lim, qname, qlen);
+
+ break;
+ }
+
+ /* FALL THROUGH */
+ default:
+ break;
+ } /* switch() */
+
+ dns__printnul(dst, lim, len);
+
+ *state = ((0xff & *state) << 0)
+ | ((0xff & srchi) << 8)
+ | ((0xff & ndots) << 16);
+
+ return len;
+} /* dns_resconf_search() */
+
+
+int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
+ unsigned i;
+ int af;
+
+ for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
+ char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
+ unsigned short port;
+
+ dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i]), addr, sizeof addr);
+ port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
+
+ if (port == 53)
+ fprintf(fp, "nameserver %s\n", addr);
+ else
+ fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
+ }
+
+
+ fprintf(fp, "search");
+
+ for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
+ fprintf(fp, " %s", resconf->search[i]);
+
+ fputc('\n', fp);
+
+
+ fprintf(fp, "lookup");
+
+ for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
+ switch (resconf->lookup[i]) {
+ case 'b':
+ fprintf(fp, " bind"); break;
+ case 'f':
+ fprintf(fp, " file"); break;
+ case 'c':
+ fprintf(fp, " cache"); break;
+ }
+ }
+
+ fputc('\n', fp);
+
+
+ fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
+
+ if (resconf->options.edns0)
+ fprintf(fp, " edns0");
+ if (resconf->options.rotate)
+ fprintf(fp, " rotate");
+ if (resconf->options.recurse)
+ fprintf(fp, " recurse");
+ if (resconf->options.smart)
+ fprintf(fp, " smart");
+
+ fputc('\n', fp);
+
+
+ if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
+ char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
+
+ dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface), addr, sizeof addr);
+
+ fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
+ }
+
+ return 0;
+} /* dns_resconf_dump() */
+
+
+/*
+ * H I N T S E R V E R R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_hints_soa {
+ unsigned char zone[DNS_D_MAXNAME + 1];
+
+ struct {
+ struct sockaddr_storage ss;
+ unsigned priority;
+ } addrs[16];
+
+ unsigned count;
+
+ struct dns_hints_soa *next;
+}; /* struct dns_hints_soa */
+
+
+struct dns_hints {
+ dns_atomic_t refcount;
+
+ struct dns_hints_soa *head;
+}; /* struct dns_hints */
+
+
+struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf EINA_UNUSED, int *error) {
+ static const struct dns_hints H_initializer;
+ struct dns_hints *H;
+
+ if (!(H = malloc(sizeof *H)))
+ goto syerr;
+
+ *H = H_initializer;
+
+ dns_hints_acquire(H);
+
+ return H;
+syerr:
+ *error = dns_syerr();
+
+ free(H);
+
+ return 0;
+} /* dns_hints_open() */
+
+
+void dns_hints_close(struct dns_hints *H) {
+ struct dns_hints_soa *soa, *nxt;
+
+ if (!H || 1 != dns_hints_release(H))
+ return /* void */;
+
+ for (soa = H->head; soa; soa = nxt) {
+ nxt = soa->next;
+
+ free(soa);
+ }
+
+ free(H);
+
+ return /* void */;
+} /* dns_hints_close() */
+
+
+unsigned dns_hints_acquire(struct dns_hints *H) {
+ return dns_atomic_inc(&H->refcount);
+} /* dns_hints_acquire() */
+
+
+unsigned dns_hints_release(struct dns_hints *H) {
+ return dns_atomic_dec(&H->refcount);
+} /* dns_hints_release() */
+
+
+struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
+ if (hints)
+ dns_hints_release(hints);
+
+ return hints;
+} /* dns_hints_mortal() */
+
+
+struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
+ struct dns_hints *hints = 0;
+ int error;
+
+ if (resconf)
+ dns_resconf_acquire(resconf);
+ else if (!(resconf = dns_resconf_local(&error)))
+ goto error;
+
+ if (!(hints = dns_hints_open(resconf, &error)))
+ goto error;
+
+ error = 0;
+
+ if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
+ goto error;
+
+ dns_resconf_close(resconf);
+
+ return hints;
+error:
+ *error_ = error;
+
+ dns_resconf_close(resconf);
+ dns_hints_close(hints);
+
+ return 0;
+} /* dns_hints_local() */
+
+
+struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
+ static const struct {
+ int af;
+ char addr[INET6_ADDRSTRLEN];
+ } root_hints[] = {
+ { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
+ { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
+ { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
+ { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
+ { AF_INET, "128.8.10.90" }, /* D.ROOT-SERVERS.NET. */
+ { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
+ { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
+ { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
+ { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
+ { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
+ { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
+ { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
+ { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
+ { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
+ };
+ struct dns_hints *hints = 0;
+ struct sockaddr_storage ss;
+ unsigned i;
+ int error, af;
+
+ if (!(hints = dns_hints_open(resconf, &error)))
+ goto error;
+
+ for (i = 0; i < lengthof(root_hints); i++) {
+ af = root_hints[i].af;
+
+ if (1 != dns_inet_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss)))
+ goto soerr;
+
+ *dns_sa_port(af, &ss) = htons(53);
+ ss.ss_family = af;
+
+ if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
+ goto error;
+ }
+
+ return hints;
+soerr:
+ error = dns_soerr();
+
+ goto error;
+error:
+ *error_ = error;
+
+ dns_hints_close(hints);
+
+ return 0;
+} /* dns_hints_root() */
+
+
+static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
+ struct dns_hints_soa *soa;
+
+ for (soa = H->head; soa; soa = soa->next) {
+ if (0 == strcasecmp(zone, (char *)soa->zone))
+ return soa;
+ }
+
+ return 0;
+} /* dns_hints_fetch() */
+
+
+int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
+ static const struct dns_hints_soa soa_initializer;
+ struct dns_hints_soa *soa;
+ unsigned i;
+
+ if (!(soa = dns_hints_fetch(H, zone))) {
+ if (!(soa = malloc(sizeof *soa)))
+ return dns_syerr();
+
+ *soa = soa_initializer;
+
+ dns__printstring(soa->zone, sizeof soa->zone, 0, zone);
+
+ soa->next = H->head;
+ H->head = soa;
+ }
+
+ i = soa->count % lengthof(soa->addrs);
+
+ memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
+
+ soa->addrs[i].priority = MAX(1, priority);
+
+ if (soa->count < lengthof(soa->addrs))
+ soa->count++;
+
+ return 0;
+} /* dns_hints_insert() */
+
+
+unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) {
+ unsigned i, n, p;
+ int error;
+
+ for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
+ if ((error = dns_hints_insert(H, zone, (struct sockaddr *)&resconf->nameserver[i], p)))
+ goto error;
+
+ p += !resconf->options.rotate;
+ }
+
+ return n;
+error:
+ *error_ = error;
+
+ return n;
+} /* dns_hints_insert_resconf() */
+
+
+static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
+ int cmp;
+
+ if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
+ return cmp;
+
+ return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
+} /* dns_hints_i_cmp() */
+
+
+static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
+ unsigned p0, p;
+
+ p0 = 0;
+
+ for (p = 1; p < soa->count; p++) {
+ if (dns_hints_i_cmp(p, p0, i, soa) < 0)
+ p0 = p;
+ }
+
+ return p0;
+} /* dns_hints_i_start() */
+
+
+static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
+ unsigned pZ, p;
+
+ for (pZ = 0; pZ < soa->count; pZ++) {
+ if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
+ goto cont;
+ }
+
+ return soa->count;
+cont:
+ for (p = pZ + 1; p < soa->count; p++) {
+ if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
+ continue;
+
+ if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
+ continue;
+
+ pZ = p;
+ }
+
+
+ return pZ;
+} /* dns_hints_i_skip() */
+
+
+struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
+ static const struct dns_hints_i i_initializer;
+ struct dns_hints_soa *soa;
+
+ i->state = i_initializer.state;
+
+ do {
+ i->state.seed = dns_random();
+ } while (0 == i->state.seed);
+
+ if ((soa = dns_hints_fetch(hints, i->zone))) {
+ i->state.next = dns_hints_i_start(i, soa);
+ }
+
+ return i;
+} /* dns_hints_i_init() */
+
+
+unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
+ struct dns_hints_soa *soa;
+ unsigned n;
+
+ if (!(soa = dns_hints_fetch(H, i->zone)))
+ return 0;
+
+ n = 0;
+
+ while (i->state.next < soa->count && n < lim) {
+ *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
+ *sa_len = dns_sa_len(*sa);
+
+ sa++;
+ sa_len++;
+ n++;
+
+ i->state.next = dns_hints_i_skip(i->state.next, i, soa);
+ }
+
+ return n;
+} /* dns_hints_grep() */
+
+
+struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
+ struct dns_packet *A, *P;
+ struct dns_rr rr;
+ char zone[DNS_D_MAXNAME + 1];
+ size_t zlen;
+ struct dns_hints_i i;
+ struct sockaddr *sa;
+ socklen_t slen;
+ int error;
+
+ if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
+ goto error;
+
+ if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
+ goto error;
+ else if (zlen >= sizeof zone)
+ goto toolong;
+
+ P = dns_p_new(512);
+ dns_header(P)->qr = 1;
+
+ if ((error = dns_rr_copy(P, &rr, Q)))
+ goto error;
+
+ if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
+ goto error;
+
+ do {
+ i.zone = zone;
+
+ dns_hints_i_init(&i, hints);
+
+ while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
+ int af = sa->sa_family;
+ int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
+
+ if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa))))
+ goto error;
+ }
+ } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
+
+ if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
+ goto error;
+
+ return A;
+toolong:
+ error = DNS_EILLEGAL;
+error:
+ *error_ = error;
+
+ return 0;
+} /* dns_hints_query() */
+
+
+/** ugly hack to support specifying ports other than 53 in resolv.conf. */
+static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
+ struct dns_hints_soa *soa;
+ unsigned short port;
+ unsigned i;
+
+ for (soa = hints->head; soa; soa = soa->next) {
+ for (i = 0; i < soa->count; i++) {
+ if (af != soa->addrs[i].ss.ss_family)
+ continue;
+
+ if (memcmp(addr, dns_sa_addr(af, &soa->addrs[i].ss), (af == AF_INET6)? sizeof (struct in6_addr) : sizeof (struct in_addr)))
+ continue;
+
+ port = *dns_sa_port(af, &soa->addrs[i].ss);
+
+ return (port)? port : htons(53);
+ }
+ }
+
+ return htons(53);
+} /* dns_hints_port() */
+
+
+int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
+ struct dns_hints_soa *soa;
+ char addr[INET6_ADDRSTRLEN];
+ unsigned i;
+ int af;
+
+ for (soa = hints->head; soa; soa = soa->next) {
+ fprintf(fp, "ZONE \"%s\"\n", soa->zone);
+
+ for (i = 0; i < soa->count; i++) {
+ af = soa->addrs[i].ss.ss_family;
+ if (!dns_inet_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss), addr, sizeof addr))
+ return dns_soerr();
+
+ fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
+ }
+ }
+
+ return 0;
+} /* dns_hints_dump() */
+
+
+/*
+ * C A C H E R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static dns_atomic_t dns_cache_acquire(struct dns_cache *cache EINA_UNUSED) {
+ return 0;
+} /* dns_cache_acquire() */
+
+
+static dns_atomic_t dns_cache_release(struct dns_cache *cache EINA_UNUSED) {
+ return 0;
+} /* dns_cache_release() */
+
+
+static struct dns_packet *dns_cache_query(struct dns_packet *query EINA_UNUSED, struct dns_cache *cache EINA_UNUSED, int *error EINA_UNUSED) {
+ return 0;
+} /* dns_cache_submit() */
+
+
+static int dns_cache_submit(struct dns_packet *query EINA_UNUSED, struct dns_cache *cache EINA_UNUSED) {
+ return 0;
+} /* dns_cache_submit() */
+
+
+static int dns_cache_check(struct dns_cache *cache EINA_UNUSED) {
+ return 0;
+} /* dns_cache_check() */
+
+
+static struct dns_packet *dns_cache_fetch(struct dns_cache *cache EINA_UNUSED, int *error EINA_UNUSED) {
+ return 0;
+} /* dns_cache_fetch() */
+
+
+static int dns_cache_pollfd(struct dns_cache *cache EINA_UNUSED) {
+ return -1;
+} /* dns_cache_pollfd() */
+
+
+static short dns_cache_events(struct dns_cache *cache EINA_UNUSED) {
+ return 0;
+} /* dns_cache_events() */
+
+
+static void dns_cache_clear(struct dns_cache *cache EINA_UNUSED) {
+ return;
+} /* dns_cache_clear() */
+
+
+struct dns_cache *dns_cache_init(struct dns_cache *cache) {
+ static const struct dns_cache c_init = {
+ .acquire = &dns_cache_acquire,
+ .release = &dns_cache_release,
+ .query = &dns_cache_query,
+ .submit = &dns_cache_submit,
+ .check = &dns_cache_check,
+ .fetch = &dns_cache_fetch,
+ .pollfd = &dns_cache_pollfd,
+ .events = &dns_cache_events,
+ .clear = &dns_cache_clear,
+ };
+
+ *cache = c_init;
+
+ return cache;
+} /* dns_cache_init() */
+
+
+void dns_cache_close(struct dns_cache *cache) {
+ if (cache)
+ cache->release(cache);
+} /* dns_cache_close() */
+
+
+/*
+ * S O C K E T R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static void dns_socketclose(int *fd) {
+ if (*fd != -1) {
+#if _WIN32
+ closesocket(*fd);
+#else
+ close(*fd);
+#endif
+ *fd = -1;
+ }
+} /* dns_socketclose() */
+
+
+#define DNS_SO_MAXTRY 7
+
+static int dns_socket(struct sockaddr *local, int type, int *error_) {
+ int error, fd = -1;
+#if defined(O_NONBLOCK)
+ int flags;
+#elif defined(FIONBIO)
+ unsigned long opt;
+#endif
+
+ if (-1 == (fd = socket(local->sa_family, type, 0)))
+ goto soerr;
+
+#if defined(F_SETFD)
+ if (-1 == fcntl(fd, F_SETFD, 1))
+ goto syerr;
+#endif
+
+#if defined(O_NONBLOCK)
+ if (-1 == (flags = fcntl(fd, F_GETFL)))
+ goto syerr;
+
+ if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ goto syerr;
+#elif defined(FIONBIO)
+ opt = 1;
+
+ if (0 != ioctlsocket(fd, FIONBIO, &opt))
+ goto soerr;
+#endif
+
+ if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
+ return fd;
+
+ if (type != SOCK_DGRAM)
+ return fd;
+
+ if (*dns_sa_port(local->sa_family, local) == 0) {
+ struct sockaddr_storage tmp;
+ unsigned i, port;
+
+ memcpy(&tmp, local, dns_sa_len(local));
+
+ for (i = 0; i < DNS_SO_MAXTRY; i++) {
+ port = 1025 + (dns_random() % 64510);
+
+ *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
+
+ if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
+ return fd;
+ }
+ }
+
+ if (0 == bind(fd, local, dns_sa_len(local)))
+ return fd;
+
+ /* FALL THROUGH */
+soerr:
+ error = dns_soerr();
+
+ goto error;
+syerr:
+ error = dns_syerr();
+
+ goto error;
+error:
+ *error_ = error;
+
+ dns_socketclose(&fd);
+
+ return -1;
+} /* dns_socket() */
+
+
+enum {
+ DNS_SO_UDP_INIT = 1,
+ DNS_SO_UDP_CONN,
+ DNS_SO_UDP_SEND,
+ DNS_SO_UDP_RECV,
+ DNS_SO_UDP_DONE,
+
+ DNS_SO_TCP_INIT,
+ DNS_SO_TCP_CONN,
+ DNS_SO_TCP_SEND,
+ DNS_SO_TCP_RECV,
+ DNS_SO_TCP_DONE,
+};
+
+struct dns_socket {
+ struct dns_options opts;
+
+ int udp;
+ int tcp;
+
+ int *old;
+ unsigned onum, olim;
+
+ int type;
+
+ struct sockaddr_storage local, remote;
+
+ struct dns_k_permutor qids;
+
+ struct dns_stat stat;
+
+ /*
+ * NOTE: dns_so_reset() zeroes everything from here down.
+ */
+ int state;
+
+ unsigned short qid;
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+ enum dns_type qtype;
+ enum dns_class qclass;
+
+ struct dns_packet *query;
+ size_t qout;
+
+ time_t began;
+
+ struct dns_packet *answer;
+ size_t alen, apos;
+}; /* struct dns_socket() */
+
+
+/*
+ * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
+ * a chance to recognize a state change after installing a persistent event
+ * and where sequential descriptors with the same integer value returned
+ * from _pollfd() would be ambiguous. See dns_so_closefds().
+ */
+static int dns_so_closefd(struct dns_socket *so, int *fd) {
+ int error;
+
+ if (*fd == -1)
+ return 0;
+
+ if (so->opts.closefd.cb) {
+ if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
+ return error;
+ } else if (*fd == -1)
+ return 0;
+ }
+
+ if (!(so->onum < so->olim)) {
+ unsigned olim = MAX(4, so->olim * 2);
+ void *old;
+
+ if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
+ return dns_syerr();
+
+ so->old = old;
+ so->olim = olim;
+ }
+
+ so->old[so->onum++] = *fd;
+ *fd = -1;
+
+ return 0;
+} /* dns_so_closefd() */
+
+
+#define DNS_SO_CLOSE_UDP 0x01
+#define DNS_SO_CLOSE_TCP 0x02
+#define DNS_SO_CLOSE_OLD 0x04
+#define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
+
+static void dns_so_closefds(struct dns_socket *so, int which) {
+ if (DNS_SO_CLOSE_UDP & which)
+ dns_socketclose(&so->udp);
+ if (DNS_SO_CLOSE_TCP & which)
+ dns_socketclose(&so->tcp);
+ if (DNS_SO_CLOSE_OLD & which) {
+ unsigned i;
+ for (i = 0; i < so->onum; i++)
+ dns_socketclose(&so->old[i]);
+ so->onum = 0;
+ free(so->old);
+ so->old = 0;
+ so->olim = 0;
+ }
+} /* dns_so_closefds() */
+
+
+static void dns_so_destroy(struct dns_socket *);
+
+static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
+ static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
+
+ *so = so_initializer;
+ so->type = type;
+
+ if (opts)
+ so->opts = *opts;
+
+ if (local)
+ memcpy(&so->local, local, dns_sa_len(local));
+
+ if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
+ goto error;
+
+ dns_k_permutor_init(&so->qids, 1, 65535);
+
+ return so;
+error:
+ dns_so_destroy(so);
+
+ return 0;
+} /* dns_so_init() */
+
+
+struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
+ struct dns_socket *so;
+
+ if (!(so = malloc(sizeof *so)))
+ goto syerr;
+
+ if (!dns_so_init(so, local, type, opts, error))
+ goto error;
+
+ return so;
+syerr:
+ *error = dns_syerr();
+error:
+ dns_so_close(so);
+
+ return 0;
+} /* dns_so_open() */
+
+
+static void dns_so_destroy(struct dns_socket *so) {
+ dns_so_reset(so);
+ dns_so_closefds(so, DNS_SO_CLOSE_ALL);
+} /* dns_so_destroy() */
+
+
+void dns_so_close(struct dns_socket *so) {
+ if (!so)
+ return;
+
+ dns_so_destroy(so);
+
+ free(so);
+} /* dns_so_close() */
+
+
+void dns_so_reset(struct dns_socket *so) {
+ free(so->answer);
+
+ memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
+} /* dns_so_reset() */
+
+
+unsigned short dns_so_mkqid(struct dns_socket *so) {
+ return dns_k_permutor_step(&so->qids);
+} /* dns_so_mkqid() */
+
+
+#define DNS_SO_MINBUF 768
+
+static int dns_so_newanswer(struct dns_socket *so, size_t len) {
+ size_t size = offsetof(struct dns_packet, data) + MAX(len, DNS_SO_MINBUF);
+ void *p;
+
+ if (!(p = realloc(so->answer, size)))
+ return dns_syerr();
+
+ so->answer = dns_p_init(p, size);
+
+ return 0;
+} /* dns_so_newanswer() */
+
+
+int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
+ struct dns_rr rr;
+ int error = -1;
+
+ dns_so_reset(so);
+
+ if ((error = dns_rr_parse(&rr, 12, Q)))
+ goto error;
+
+ if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
+ goto error;
+ /*
+ * NOTE: don't bail if expansion is too long; caller may be
+ * intentionally sending long names. However, we won't be able to
+ * verify it on return.
+ */
+
+ so->qtype = rr.type;
+ so->qclass = rr.class;
+
+ if ((error = dns_so_newanswer(so, DNS_SO_MINBUF)))
+ goto syerr;
+
+ memcpy(&so->remote, host, dns_sa_len(host));
+
+ so->query = Q;
+ so->qout = 0;
+ so->began = dns_now();
+
+ if (dns_header(so->query)->qid == 0)
+ dns_header(so->query)->qid = dns_so_mkqid(so);
+
+ so->qid = dns_header(so->query)->qid;
+ so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
+
+ so->stat.queries++;
+
+ return 0;
+syerr:
+ error = dns_syerr();
+error:
+ dns_so_reset(so);
+
+ return error;
+} /* dns_so_submit() */
+
+
+static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+ struct dns_rr rr;
+ int error = -1;
+
+ if (so->qid != dns_header(so->answer)->qid)
+ return DNS_EUNKNOWN;
+
+ if (!dns_p_count(so->answer, DNS_S_QD))
+ return DNS_EUNKNOWN;
+
+ if (0 != dns_rr_parse(&rr, 12, so->answer))
+ return DNS_EUNKNOWN;
+
+ if (rr.type != so->qtype || rr.class != so->qclass)
+ return DNS_EUNKNOWN;
+
+ if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
+ return error;
+ else if (qlen >= sizeof qname || qlen != so->qlen)
+ return DNS_EUNKNOWN;
+
+ if (0 != strcasecmp(so->qname, qname))
+ return DNS_EUNKNOWN;
+
+ return 0;
+} /* dns_so_verify() */
+
+
+static int dns_so_tcp_send(struct dns_socket *so) {
+ unsigned char *qsrc;
+ size_t qend;
+ long n;
+
+ so->query->data[-2] = 0xff & (so->query->end >> 8);
+ so->query->data[-1] = 0xff & (so->query->end >> 0);
+
+ qsrc = &so->query->data[-2] + so->qout;
+ qend = so->query->end + 2;
+
+ while (so->qout < qend) {
+ if (0 > (n = send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0)))
+ return dns_soerr();
+
+ so->qout += n;
+ so->stat.tcp.sent.bytes += n;
+ }
+
+ so->stat.tcp.sent.count++;
+
+ return 0;
+} /* dns_so_tcp_send() */
+
+
+static int dns_so_tcp_recv(struct dns_socket *so) {
+ unsigned char *asrc;
+ size_t aend, alen;
+ int error;
+ long n;
+
+ aend = so->alen + 2;
+
+ while (so->apos < aend) {
+ asrc = &so->answer->data[-2];
+
+ if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0)))
+ return dns_soerr();
+ else if (n == 0)
+ return DNS_EUNKNOWN; /* FIXME */
+
+ so->apos += n;
+ so->stat.tcp.rcvd.bytes += n;
+
+ if (so->alen == 0 && so->apos >= 2) {
+ alen = ((0xff & so->answer->data[-2]) << 8)
+ | ((0xff & so->answer->data[-1]) << 0);
+
+ if ((error = dns_so_newanswer(so, alen)))
+ return error;
+
+ so->alen = alen;
+ aend = alen + 2;
+ }
+ }
+
+ so->answer->end = so->alen;
+ so->stat.tcp.rcvd.count++;
+
+ return 0;
+} /* dns_so_tcp_recv() */
+
+
+int dns_so_check(struct dns_socket *so) {
+ int error;
+ long n;
+
+retry:
+ switch (so->state) {
+ case DNS_SO_UDP_INIT:
+ so->state++;
+ case DNS_SO_UDP_CONN:
+ if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
+ goto soerr;
+
+ so->state++;
+ case DNS_SO_UDP_SEND:
+ if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0)))
+ goto soerr;
+
+ so->stat.udp.sent.bytes += n;
+ so->stat.udp.sent.count++;
+
+ so->state++;
+ case DNS_SO_UDP_RECV:
+ if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0)))
+ goto soerr;
+
+ so->stat.udp.rcvd.bytes += n;
+ so->stat.udp.rcvd.count++;
+
+ if ((so->answer->end = n) < 12)
+ goto trash;
+
+ if ((error = dns_so_verify(so, so->answer)))
+ goto trash;
+
+ so->state++;
+ case DNS_SO_UDP_DONE:
+ if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM)
+ return 0;
+
+ so->state++;
+ case DNS_SO_TCP_INIT:
+ if ((error = dns_so_closefd(so, &so->tcp)))
+ goto error;
+
+ if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
+ goto error;
+
+ so->state++;
+ case DNS_SO_TCP_CONN:
+ if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) {
+ if (dns_soerr() != DNS_EISCONN)
+ goto soerr;
+ }
+
+ so->state++;
+ case DNS_SO_TCP_SEND:
+ if ((error = dns_so_tcp_send(so)))
+ goto error;
+
+ so->state++;
+ case DNS_SO_TCP_RECV:
+ if ((error = dns_so_tcp_recv(so)))
+ goto error;
+
+ so->state++;
+ case DNS_SO_TCP_DONE:
+ if ((error = dns_so_closefd(so, &so->tcp)))
+ goto error;
+
+ if (so->answer->end < 12)
+ return DNS_EILLEGAL;
+
+ if ((error = dns_so_verify(so, so->answer)))
+ goto error;
+
+ return 0;
+ default:
+ error = DNS_EUNKNOWN;
+
+ goto error;
+ } /* switch() */
+
+trash:
+ goto retry;
+soerr:
+ error = dns_soerr();
+
+ goto error;
+error:
+ switch (error) {
+ case DNS_EINTR:
+ goto retry;
+ case DNS_EINPROGRESS:
+ /* FALL THROUGH */
+ case DNS_EALREADY:
+ /* FALL THROUGH */
+#if DNS_EWOULDBLOCK != DNS_EAGAIN
+ case DNS_EWOULDBLOCK:
+ /* FALL THROUGH */
+#endif
+ error = DNS_EAGAIN;
+
+ break;
+ } /* switch() */
+
+ return error;
+} /* dns_so_check() */
+
+
+struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
+ struct dns_packet *answer;
+
+ switch (so->state) {
+ case DNS_SO_UDP_DONE:
+ case DNS_SO_TCP_DONE:
+ answer = so->answer;
+ so->answer = 0;
+
+ return answer;
+ default:
+ *error = DNS_EUNKNOWN;
+
+ return 0;
+ }
+} /* dns_so_fetch() */
+
+
+struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
+ struct dns_packet *A;
+ int error;
+
+ if (!so->state) {
+ if ((error = dns_so_submit(so, Q, host)))
+ goto error;
+ }
+
+ if ((error = dns_so_check(so)))
+ goto error;
+
+ if (!(A = dns_so_fetch(so, &error)))
+ goto error;
+
+ dns_so_reset(so);
+
+ return A;
+error:
+ *error_ = error;
+
+ return 0;
+} /* dns_so_query() */
+
+
+time_t dns_so_elapsed(struct dns_socket *so) {
+ return dns_elapsed(so->began);
+} /* dns_so_elapsed() */
+
+
+void dns_so_clear(struct dns_socket *so) {
+ dns_so_closefds(so, DNS_SO_CLOSE_OLD);
+} /* dns_so_clear() */
+
+
+static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
+ int events = 0;
+
+ switch (so->state) {
+ case DNS_SO_UDP_CONN:
+ case DNS_SO_UDP_SEND:
+ events |= DNS_POLLOUT;
+
+ break;
+ case DNS_SO_UDP_RECV:
+ events |= DNS_POLLIN;
+
+ break;
+ case DNS_SO_TCP_CONN:
+ case DNS_SO_TCP_SEND:
+ events |= DNS_POLLOUT;
+
+ break;
+ case DNS_SO_TCP_RECV:
+ events |= DNS_POLLIN;
+
+ break;
+ } /* switch() */
+
+ switch (type) {
+ case DNS_LIBEVENT:
+ return DNS_POLL2EV(events);
+ default:
+ return events;
+ } /* switch() */
+} /* dns_so_events2() */
+
+
+int dns_so_events(struct dns_socket *so) {
+ return dns_so_events2(so, so->opts.events);
+} /* dns_so_events() */
+
+
+int dns_so_pollfd(struct dns_socket *so) {
+ switch (so->state) {
+ case DNS_SO_UDP_CONN:
+ case DNS_SO_UDP_SEND:
+ case DNS_SO_UDP_RECV:
+ return so->udp;
+ case DNS_SO_TCP_CONN:
+ case DNS_SO_TCP_SEND:
+ case DNS_SO_TCP_RECV:
+ return so->tcp;
+ } /* switch() */
+
+ return -1;
+} /* dns_so_pollfd() */
+
+
+int dns_so_poll(struct dns_socket *so, int timeout) {
+ return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
+} /* dns_so_poll() */
+
+
+const struct dns_stat *dns_so_stat(struct dns_socket *so) {
+ return &so->stat;
+} /* dns_so_stat() */
+
+
+/*
+ * R E S O L V E R R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+enum dns_res_state {
+ DNS_R_INIT,
+ DNS_R_GLUE,
+ DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
+
+ DNS_R_FILE, /* Lookup in local hosts database */
+
+ DNS_R_CACHE, /* Lookup in application cache */
+ DNS_R_SUBMIT,
+ DNS_R_CHECK,
+ DNS_R_FETCH,
+
+ DNS_R_BIND, /* Lookup in the network */
+ DNS_R_SEARCH,
+ DNS_R_HINTS,
+ DNS_R_ITERATE,
+ DNS_R_FOREACH_NS,
+ DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
+ DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
+ DNS_R_FOREACH_A,
+ DNS_R_QUERY_A,
+ DNS_R_CNAME0_A,
+ DNS_R_CNAME1_A,
+
+ DNS_R_FINISH,
+ DNS_R_SMART0_A,
+ DNS_R_SMART1_A,
+ DNS_R_DONE,
+ DNS_R_SERVFAIL,
+}; /* enum dns_res_state */
+
+
+#define DNS_R_MAXDEPTH 8
+#define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
+
+struct dns_resolver {
+ struct dns_socket so;
+
+ struct dns_resolv_conf *resconf;
+ struct dns_hosts *hosts;
+ struct dns_hints *hints;
+ struct dns_cache *cache;
+
+ dns_atomic_t refcount;
+
+ /* Reset zeroes everything below here. */
+
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+
+ enum dns_type qtype;
+ enum dns_class qclass;
+
+ time_t began;
+
+ dns_resconf_i_t search;
+
+ struct dns_rr_i smart;
+
+ struct dns_res_frame {
+ enum dns_res_state state;
+
+ int error;
+ int which; /* (B)IND, (F)ILE; index into resconf->lookup */
+
+ unsigned attempts;
+
+ struct dns_packet *query, *answer, *hints;
+
+ struct dns_rr_i hints_i, hints_j;
+ struct dns_rr hints_ns, ans_cname;
+ } stack[DNS_R_MAXDEPTH];
+
+ unsigned sp;
+}; /* struct dns_resolver */
+
+
+static int dns_res_tcp2type(int tcp) {
+ switch (tcp) {
+ case DNS_RESCONF_TCP_ONLY:
+ return SOCK_STREAM;
+ case DNS_RESCONF_TCP_DISABLE:
+ return SOCK_DGRAM;
+ default:
+ return 0;
+ }
+} /* dns_res_tcp2type() */
+
+struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *error_) {
+ static const struct dns_resolver R_initializer
+ = { .refcount = 1, };
+ struct dns_resolver *R = 0;
+ int type, error;
+
+ /*
+ * Grab ref count early because the caller may have passed us a mortal
+ * reference, and we want to do the right thing if we return early
+ * from an error.
+ */
+ if (resconf)
+ dns_resconf_acquire(resconf);
+ if (hosts)
+ dns_hosts_acquire(hosts);
+ if (hints)
+ dns_hints_acquire(hints);
+ if (cache)
+ dns_cache_acquire(cache);
+
+ /*
+ * Don't try to load it ourselves because a NULL object might be an
+ * error from, say, dns_resconf_root(), and loading
+ * dns_resconf_local() by default would create undesirable surpises.
+ */
+ if (!resconf || !hosts || !hints)
+ goto error;
+
+ if (!(R = malloc(sizeof *R)))
+ goto syerr;
+
+ *R = R_initializer;
+ type = dns_res_tcp2type(resconf->options.tcp);
+
+ if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
+ goto error;
+
+ R->resconf = resconf;
+ R->hosts = hosts;
+ R->hints = hints;
+ R->cache = cache;
+
+ return R;
+syerr:
+ error = dns_syerr();
+error:
+ *error_ = error;
+
+ dns_res_close(R);
+
+ dns_resconf_close(resconf);
+ dns_hosts_close(hosts);
+ dns_hints_close(hints);
+ dns_cache_close(cache);
+
+ return 0;
+} /* dns_res_open() */
+
+
+struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
+ struct dns_resolv_conf *resconf = 0;
+ struct dns_hosts *hosts = 0;
+ struct dns_hints *hints = 0;
+ struct dns_resolver *res = 0;
+
+ if (!(resconf = dns_resconf_local(error)))
+ goto epilog;
+
+ if (!(hosts = dns_hosts_local(error)))
+ goto epilog;
+
+ if (!(hints = dns_hints_local(resconf, error)))
+ goto epilog;
+
+ if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
+ goto epilog;
+
+epilog:
+ dns_resconf_close(resconf);
+ dns_hosts_close(hosts);
+ dns_hints_close(hints);
+
+ return res;
+} /* dns_res_stub() */
+
+
+static void dns_res_reset_frame(struct dns_resolver *R EINA_UNUSED, struct dns_res_frame *frame) {
+ free(frame->query);
+ free(frame->answer);
+ free(frame->hints);
+
+ memset(frame, '\0', sizeof *frame);
+} /* dns_res_reset_frame() */
+
+
+void dns_res_reset(struct dns_resolver *R) {
+ unsigned i;
+
+ dns_so_reset(&R->so);
+
+ for (i = 0; i < lengthof(R->stack); i++)
+ dns_res_reset_frame(R, &R->stack[i]);
+
+ memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
+} /* dns_res_reset() */
+
+
+void dns_res_close(struct dns_resolver *R) {
+ if (!R || 1 < dns_res_release(R))
+ return;
+
+ dns_res_reset(R);
+
+ dns_so_destroy(&R->so);
+
+ dns_hints_close(R->hints);
+ dns_hosts_close(R->hosts);
+ dns_resconf_close(R->resconf);
+ dns_cache_close(R->cache);
+
+ free(R);
+} /* dns_res_close() */
+
+
+unsigned dns_res_acquire(struct dns_resolver *R) {
+ return dns_atomic_inc(&R->refcount);
+} /* dns_res_acquire() */
+
+
+unsigned dns_res_release(struct dns_resolver *R) {
+ return dns_atomic_dec(&R->refcount);
+} /* dns_res_release() */
+
+
+struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
+ if (res)
+ dns_res_release(res);
+ return res;
+} /* dns_res_mortal() */
+
+
+static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
+ size_t bufsiz = P0->end + P1->end;
+ struct dns_packet *P[3] = { P0, P1, 0 };
+ struct dns_rr rr[3];
+ int error, copy, i;
+ enum dns_section section;
+
+retry:
+ if (!(P[2] = dns_p_make(bufsiz, &error)))
+ goto error;
+
+ dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
+ if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
+ goto error;
+ }
+
+ for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
+ for (i = 0; i < 2; i++) {
+ dns_rr_foreach(&rr[i], P[i], .section = section) {
+ copy = 1;
+
+ dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
+ if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
+ copy = 0;
+
+ break;
+ }
+ }
+
+ if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
+ if (error == DNS_ENOBUFS && bufsiz < 65535) {
+ free(P[2]); P[2] = 0;
+
+ bufsiz = MAX(65535, bufsiz * 2);
+
+ goto retry;
+ }
+
+ goto error;
+ }
+ } /* foreach(rr) */
+ } /* foreach(packet) */
+ } /* foreach(section) */
+
+ return P[2];
+error:
+ *error_ = error;
+
+ free(P[2]);
+
+ return 0;
+} /* dns_res_merge() */
+
+
+static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
+ struct dns_packet *P = dns_p_new(512);
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+ enum dns_type qtype;
+ struct dns_rr rr;
+ unsigned sp;
+ int error;
+
+ if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
+ || qlen >= sizeof qname)
+ return 0;
+
+ if (!(qtype = dns_rr_type(12, Q)))
+ return 0;
+
+ if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
+ return 0;
+
+ for (sp = 0; sp <= R->sp; sp++) {
+ if (!R->stack[sp].answer)
+ continue;
+
+ dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
+ rr.section = DNS_S_AN;
+
+ if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
+ return 0;
+ }
+ }
+
+ if (dns_p_count(P, DNS_S_AN) > 0)
+ goto copy;
+
+ /* Otherwise, look for a CNAME */
+ for (sp = 0; sp <= R->sp; sp++) {
+ if (!R->stack[sp].answer)
+ continue;
+
+ dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
+ rr.section = DNS_S_AN;
+
+ if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
+ return 0;
+ }
+ }
+
+ if (!dns_p_count(P, DNS_S_AN))
+ return 0;
+
+copy:
+ return dns_p_copy(dns_p_make(P->end, &error), P);
+} /* dns_res_glue() */
+
+
+static struct dns_packet *dns_res_mkquery(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass, int *error_) {
+ struct dns_packet *Q = 0;
+ int error;
+
+ if (!(Q = dns_p_init(malloc(DNS_P_QBUFSIZ), DNS_P_QBUFSIZ)))
+ goto syerr;
+
+ if ((error = dns_p_push(Q, DNS_S_QD, qname, strlen(qname), qtype, qclass, 0, 0)))
+ goto error;
+
+ dns_header(Q)->rd = !R->resconf->options.recurse;
+
+ return Q;
+syerr:
+ error = dns_syerr();
+error:
+ free(Q);
+
+ *error_ = error;
+
+ return 0;
+} /* dns_res_mkquery() */
+
+
+/*
+ * Sort NS records by three criteria:
+ *
+ * 1) Whether glue is present.
+ * 2) Whether glue record is original or of recursive lookup.
+ * 3) Randomly shuffle records which share the above criteria.
+ *
+ * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
+ * be added during an iteration.
+ *
+ * FIXME: Only groks A glue, not AAAA glue.
+ */
+static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
+ _Bool glued[2] = { 0 };
+ struct dns_ns ns;
+ struct dns_rr x, y;
+ int cmp, error;
+
+ if (!(error = dns_ns_parse(&ns, a, P)))
+ if (!(glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error)))
+ x.dn.p = 0;
+
+ if (!(error = dns_ns_parse(&ns, b, P)))
+ if (!(glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error)))
+ y.dn.p = 0;
+
+ if ((cmp = glued[1] - glued[0]))
+ return cmp;
+ else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0])))
+ return cmp;
+ else
+ return dns_rr_i_shuffle(a, b, i, P);
+} /* dns_res_nameserv_cmp() */
+
+
+#define goto(sp, i) \
+ do { R->stack[(sp)].state = (i); goto exec; } while (0)
+
+static int dns_res_exec(struct dns_resolver *R) {
+ struct dns_res_frame *F;
+ struct dns_packet *P;
+ char host[DNS_D_MAXNAME + 1];
+ size_t len;
+ struct dns_rr rr;
+ struct sockaddr_in sin;
+ int error;
+
+exec:
+
+ F = &R->stack[R->sp];
+
+ switch (F->state) {
+ case DNS_R_INIT:
+ F->state++;
+ case DNS_R_GLUE:
+ if (R->sp == 0)
+ goto(R->sp, DNS_R_SWITCH);
+
+ assert(F->query);
+
+ if (!(F->answer = dns_res_glue(R, F->query)))
+ goto(R->sp, DNS_R_SWITCH);
+
+ if (!(len = dns_d_expand(host, sizeof host, 12, F->query, &error)))
+ goto error;
+ else if (len >= sizeof host)
+ goto toolong;
+
+ dns_rr_foreach(&rr, F->answer, .name = host, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
+ goto(R->sp, DNS_R_FINISH);
+ }
+
+ dns_rr_foreach(&rr, F->answer, .name = host, .type = DNS_T_CNAME, .section = DNS_S_AN) {
+ F->ans_cname = rr;
+
+ goto(R->sp, DNS_R_CNAME0_A);
+ }
+
+ F->state++;
+ case DNS_R_SWITCH:
+ while (F->which < (int)sizeof R->resconf->lookup) {
+ switch (R->resconf->lookup[F->which++]) {
+ case 'b': case 'B':
+ goto(R->sp, DNS_R_BIND);
+ case 'f': case 'F':
+ goto(R->sp, DNS_R_FILE);
+ case 'c': case 'C':
+ if (R->cache)
+ goto(R->sp, DNS_R_CACHE);
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ goto(R->sp, DNS_R_SERVFAIL); /* FIXME: Right behavior? */
+ case DNS_R_FILE:
+ if (R->sp > 0) {
+ free(F->answer);
+
+ if (!(F->answer = dns_hosts_query(R->hosts, F->query, &error)))
+ goto error;
+
+ if (dns_p_count(F->answer, DNS_S_AN) > 0)
+ goto(R->sp, DNS_R_FINISH);
+
+ free(F->answer); F->answer = 0;
+ } else {
+ R->search = 0;
+
+ while ((len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) {
+/*
+ * FIXME: Some sort of bug, either with this code or with GCC 3.3.5 on
+ * OpenBSD 4.4, overwites the stack guard. If the bug is in this file, it
+ * appears to be localized somewhere around here. It can also be mitigated
+ * in dns_hosts_query(). In any event, the bug manifests only when using
+ * compound literals. alloca(), malloc(), calloc(), etc, all work fine.
+ * Valgrind (tested on Linux) cannot detect any issues, but stack issues are
+ * not Valgrind's forte. Neither can I spot anything in the assembly, but
+ * that's not my forte.
+ */
+#if __OpenBSD__ && __GNUC__
+ struct dns_packet *query = __builtin_alloca(DNS_P_QBUFSIZ);
+
+ dns_p_init(query, DNS_P_QBUFSIZ);
+#else
+ struct dns_packet *query = dns_p_new(DNS_P_QBUFSIZ);
+#endif
+
+ if ((error = dns_p_push(query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0)))
+ goto error;
+
+ free(F->answer);
+
+ if (!(F->answer = dns_hosts_query(R->hosts, query, &error)))
+ goto error;
+
+ if (dns_p_count(F->answer, DNS_S_AN) > 0)
+ goto(R->sp, DNS_R_FINISH);
+
+ free(F->answer); F->answer = 0;
+ }
+ }
+
+ goto(R->sp, DNS_R_SWITCH);
+ case DNS_R_CACHE:
+ error = 0;
+
+ if (!F->query && !(F->query = dns_res_mkquery(R, R->qname, R->qtype, R->qclass, &error)))
+ goto error;
+
+ free(F->answer);
+
+ if ((F->answer = R->cache->query(F->query, R->cache, &error))) {
+ if (dns_p_count(F->answer, DNS_S_AN) > 0)
+ goto(R->sp, DNS_R_FINISH);
+
+ free(F->answer); F->answer = 0;
+
+ goto(R->sp, DNS_R_SWITCH);
+ } else if (error)
+ goto error;
+
+ F->state++;
+ case DNS_R_SUBMIT:
+ if ((error = R->cache->submit(F->query, R->cache)))
+ goto error;
+
+ F->state++;
+ case DNS_R_CHECK:
+ if ((error = R->cache->check(R->cache)))
+ goto error;
+
+ F->state++;
+ case DNS_R_FETCH:
+ error = 0;
+
+ free(F->answer);
+
+ if ((F->answer = R->cache->fetch(R->cache, &error))) {
+ if (dns_p_count(F->answer, DNS_S_AN) > 0)
+ goto(R->sp, DNS_R_FINISH);
+
+ free(F->answer); F->answer = 0;
+
+ goto(R->sp, DNS_R_SWITCH);
+ } else if (error)
+ goto error;
+
+ goto(R->sp, DNS_R_SWITCH);
+ case DNS_R_BIND:
+ if (R->sp > 0) {
+ assert(F->query);
+
+ goto(R->sp, DNS_R_HINTS);
+ }
+
+ R->search = 0;
+
+ F->state++;
+ case DNS_R_SEARCH:
+ if (!(len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search)))
+ goto(R->sp, DNS_R_SWITCH);
+
+ if (!(P = dns_p_make(DNS_P_QBUFSIZ, &error)))
+ goto error;
+
+ dns_header(P)->rd = !R->resconf->options.recurse;
+
+ free(F->query); F->query = P;
+
+ if ((error = dns_p_push(F->query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0)))
+ goto error;
+
+ F->state++;
+ case DNS_R_HINTS:
+ if (!(F->hints = dns_hints_query(R->hints, F->query, &error)))
+ goto error;
+
+ F->state++;
+ case DNS_R_ITERATE:
+ dns_rr_i_init(&F->hints_i, F->hints);
+
+ F->hints_i.section = DNS_S_AUTHORITY;
+ F->hints_i.type = DNS_T_NS;
+ F->hints_i.sort = &dns_res_nameserv_cmp;
+ F->hints_i.args[0] = F->hints->end;
+
+ F->state++;
+ case DNS_R_FOREACH_NS:
+ dns_rr_i_save(&F->hints_i);
+
+ /* Load our next nameserver host. */
+ if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
+ if (++F->attempts < R->resconf->options.attempts)
+ goto(R->sp, DNS_R_ITERATE);
+
+ goto(R->sp, DNS_R_SWITCH);
+ }
+
+ dns_rr_i_init(&F->hints_j, F->hints);
+
+ /* Assume there are glue records */
+ goto(R->sp, DNS_R_FOREACH_A);
+ case DNS_R_RESOLV0_NS:
+ /* Have we reached our max depth? */
+ if (&F[1] >= endof(R->stack))
+ goto(R->sp, DNS_R_FOREACH_NS);
+
+ dns_res_reset_frame(R, &F[1]);
+
+ if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error)))
+ goto error;
+
+ if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints)))
+ goto error;
+
+ if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), DNS_T_A, DNS_C_IN, 0, 0)))
+ goto error;
+
+ F->state++;
+
+ goto(++R->sp, DNS_R_INIT);
+ case DNS_R_RESOLV1_NS:
+ if (!(len = dns_d_expand(host, sizeof host, 12, F[1].query, &error)))
+ goto error;
+ else if (len >= sizeof host)
+ goto toolong;
+
+ dns_rr_foreach(&rr, F[1].answer, .name = host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
+ rr.section = DNS_S_AR;
+
+ if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
+ goto error;
+
+ dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
+ }
+
+ goto(R->sp, DNS_R_FOREACH_NS);
+ case DNS_R_FOREACH_A:
+ /*
+ * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
+ * this state is re-entrant, but we need to reset
+ * .name to a valid pointer each time.
+ */
+ if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints)))
+ goto error;
+
+ F->hints_j.name = host;
+ F->hints_j.type = DNS_T_A;
+ F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
+
+ if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
+ if (!dns_rr_i_count(&F->hints_j))
+ goto(R->sp, DNS_R_RESOLV0_NS);
+
+ goto(R->sp, DNS_R_FOREACH_NS);
+ }
+
+ sin.sin_family = AF_INET;
+
+ if ((error = dns_a_parse((struct dns_a *)&sin.sin_addr, &rr, F->hints)))
+ goto error;
+
+ if (R->sp == 0)
+ sin.sin_port = dns_hints_port(R->hints, AF_INET, (struct sockaddr *)&sin.sin_addr);
+ else
+ sin.sin_port = htons(53);
+
+ if (DNS_DEBUG) {
+ char addr[INET_ADDRSTRLEN + 1];
+ dns_a_print(addr, sizeof addr, (struct dns_a *)&sin.sin_addr);
+ DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", host, addr, R->sp);
+ }
+
+ if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
+ goto error;
+
+ F->state++;
+ case DNS_R_QUERY_A:
+ if (dns_so_elapsed(&R->so) >= (time_t)R->resconf->options.timeout)
+ goto(R->sp, DNS_R_FOREACH_A);
+
+ if ((error = dns_so_check(&R->so)))
+ goto error;
+
+ free(F->answer);
+
+ if (!(F->answer = dns_so_fetch(&R->so, &error)))
+ goto error;
+
+ if (DNS_DEBUG) {
+ DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
+ }
+
+ if ((error = dns_rr_parse(&rr, 12, F->query)))
+ goto error;
+
+ if (!(len = dns_d_expand(host, sizeof host, rr.dn.p, F->query, &error)))
+ goto error;
+ else if (len >= sizeof host)
+ goto toolong;
+
+ dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = rr.type) {
+ goto(R->sp, DNS_R_FINISH); /* Found */
+ }
+
+ dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = DNS_T_CNAME) {
+ F->ans_cname = rr;
+
+ goto(R->sp, DNS_R_CNAME0_A);
+ }
+
+ if (!R->resconf->options.recurse)
+ goto(R->sp, DNS_R_SWITCH);
+
+ dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
+ free(F->hints);
+
+ F->hints = F->answer;
+ F->answer = 0;
+
+ goto(R->sp, DNS_R_ITERATE);
+ }
+
+ /* XXX: Should this go further up? */
+ if (dns_header(F->answer)->aa)
+ goto(R->sp, DNS_R_FINISH);
+
+ goto(R->sp, DNS_R_FOREACH_A);
+ case DNS_R_CNAME0_A:
+ if (&F[1] >= endof(R->stack))
+ goto(R->sp, DNS_R_FINISH);
+
+ if ((error = dns_cname_parse((struct dns_cname *)host, &F->ans_cname, F->answer)))
+ goto error;
+
+ dns_res_reset_frame(R, &F[1]);
+
+ if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error)))
+ goto error;
+
+ if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), dns_rr_type(12, F->query), DNS_C_IN, 0, 0)))
+ goto error;
+
+ F->state++;
+
+ goto(++R->sp, DNS_R_INIT);
+ case DNS_R_CNAME1_A:
+ if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
+ goto error;
+
+ free(F->answer); F->answer = P;
+
+ goto(R->sp, DNS_R_FINISH);
+ case DNS_R_FINISH:
+ assert(F->answer);
+
+ if (!R->resconf->options.smart || R->sp > 0)
+ goto(R->sp, DNS_R_DONE);
+
+ R->smart.section = DNS_S_AN;
+ R->smart.type = R->qtype;
+
+ dns_rr_i_init(&R->smart, F->answer);
+
+ F->state++;
+ case DNS_R_SMART0_A:
+ if (&F[1] >= endof(R->stack))
+ goto(R->sp, DNS_R_DONE);
+
+ while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
+ union {
+ struct dns_ns ns;
+ struct dns_mx mx;
+ struct dns_srv srv;
+ } rd;
+ const char *qname;
+ enum dns_type qtype;
+ enum dns_class qclass;
+
+ switch (rr.type) {
+ case DNS_T_NS:
+ if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
+ goto error;
+
+ qname = rd.ns.host;
+ qtype = DNS_T_A;
+ qclass = DNS_C_IN;
+
+ break;
+ case DNS_T_MX:
+ if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
+ goto error;
+
+ qname = rd.mx.host;
+ qtype = DNS_T_A;
+ qclass = DNS_C_IN;
+
+ break;
+ case DNS_T_SRV:
+ if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
+ goto error;
+
+ qname = rd.srv.target;
+ qtype = DNS_T_A;
+ qclass = DNS_C_IN;
+
+ break;
+ default:
+ continue;
+ } /* switch() */
+
+ dns_res_reset_frame(R, &F[1]);
+
+ if (!(F[1].query = dns_res_mkquery(R, qname, qtype, qclass, &error)))
+ goto error;
+
+ F->state++;
+
+ goto(++R->sp, DNS_R_INIT);
+ } /* while() */
+
+ /*
+ * NOTE: SMTP specification says to fallback to A record.
+ *
+ * XXX: Should we add a mock MX answer?
+ */
+ if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
+ dns_res_reset_frame(R, &F[1]);
+
+ if (!(F[1].query = dns_res_mkquery(R, R->qname, DNS_T_A, DNS_C_IN, &error)))
+ goto error;
+
+ R->smart.state.count++;
+ F->state++;
+
+ goto(++R->sp, DNS_R_INIT);
+ }
+
+ goto(R->sp, DNS_R_DONE);
+ case DNS_R_SMART1_A:
+ assert(F[1].answer);
+
+ /*
+ * FIXME: For CNAME chains (which are typically illegal in
+ * this context), we should rewrite the record host name
+ * to the original smart qname. All the user cares about
+ * is locating that A/AAAA record.
+ */
+ dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
+ rr.section = DNS_S_AR;
+
+ if (dns_rr_exists(&rr, F[1].answer, F->answer))
+ continue;
+
+ while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
+ if (error != DNS_ENOBUFS)
+ goto error;
+ if ((error = dns_p_grow(&F->answer)))
+ goto error;
+ }
+ }
+
+ goto(R->sp, DNS_R_SMART0_A);
+ case DNS_R_DONE:
+ assert(F->answer);
+
+ if (R->sp > 0)
+ goto(--R->sp, F[-1].state);
+
+ break;
+ case DNS_R_SERVFAIL:
+ free(F->answer);
+
+ if (!(F->answer = dns_p_make(DNS_P_QBUFSIZ, &error)))
+ goto error;
+
+ dns_header(F->answer)->qr = 1;
+ dns_header(F->answer)->rcode = DNS_RC_SERVFAIL;
+
+ if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
+ goto error;
+
+ goto(R->sp, DNS_R_DONE);
+ default:
+ error = EINVAL;
+
+ goto error;
+ } /* switch () */
+
+ return 0;
+toolong:
+ error = DNS_EILLEGAL;
+error:
+ return error;
+} /* dns_res_exec() */
+
+#undef goto
+
+
+void dns_res_clear(struct dns_resolver *R) {
+ switch (R->stack[R->sp].state) {
+ case DNS_R_CHECK:
+ return R->cache->clear(R->cache);
+ default:
+ return dns_so_clear(&R->so);
+ }
+} /* dns_res_clear() */
+
+
+static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
+ int events;
+
+ switch (R->stack[R->sp].state) {
+ case DNS_R_CHECK:
+ events = R->cache->events(R->cache);
+
+ return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
+ default:
+ return dns_so_events2(&R->so, type);
+ }
+} /* dns_res_events2() */
+
+
+int dns_res_events(struct dns_resolver *R) {
+ return dns_res_events2(R, R->so.opts.events);
+} /* dns_res_events() */
+
+
+int dns_res_pollfd(struct dns_resolver *R) {
+ switch (R->stack[R->sp].state) {
+ case DNS_R_CHECK:
+ return R->cache->pollfd(R->cache);
+ default:
+ return dns_so_pollfd(&R->so);
+ }
+} /* dns_res_pollfd() */
+
+
+time_t dns_res_elapsed(struct dns_resolver *R) {
+ return dns_elapsed(R->began);
+} /* dns_res_elapsed() */
+
+
+int dns_res_poll(struct dns_resolver *R, int timeout) {
+ return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
+} /* dns_res_poll() */
+
+
+int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
+ dns_res_reset(R);
+
+ /* Don't anchor; that can conflict with searchlist generation. */
+ dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = strlen(qname)), 0);
+
+ R->qtype = qtype;
+ R->qclass = qclass;
+
+ R->began = dns_now();
+
+ return 0;
+} /* dns_res_submit() */
+
+
+int dns_res_check(struct dns_resolver *R) {
+ int error;
+
+ if ((error = dns_res_exec(R)))
+ return error;
+
+ return 0;
+} /* dns_res_check() */
+
+
+struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) {
+ struct dns_packet *answer;
+
+ if (R->stack[0].state != DNS_R_DONE) {
+ *error = DNS_EUNKNOWN;
+
+ return 0;
+ }
+
+ answer = R->stack[0].answer;
+ R->stack[0].answer = 0;
+
+ return answer;
+} /* dns_res_fetch() */
+
+
+struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) {
+ int error;
+
+ if ((error = dns_res_submit(res, qname, qtype, qclass)))
+ goto error;
+
+ while ((error = dns_res_check(res))) {
+ if (dns_res_elapsed(res) > timeout)
+ error = DNS_ETIMEDOUT;
+
+ if (error != DNS_EAGAIN)
+ goto error;
+
+ if ((error = dns_res_poll(res, 1)))
+ goto error;
+ }
+
+ return dns_res_fetch(res, error_);
+error:
+ *error_ = error;
+
+ return 0;
+} /* dns_res_query() */
+
+
+const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
+ return dns_so_stat(&res->so);
+} /* dns_res_stat() */
+
+
+/*
+ * A D D R I N F O R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_addrinfo {
+ struct addrinfo hints;
+ struct dns_resolver *res;
+
+ char qname[DNS_D_MAXNAME + 1];
+ enum dns_type qtype;
+ unsigned short qport, port;
+
+ struct dns_packet *answer;
+ struct dns_packet *glue;
+
+ struct dns_rr_i i, g;
+ struct dns_rr rr;
+
+ char cname[DNS_D_MAXNAME + 1];
+
+ int state;
+}; /* struct dns_addrinfo */
+
+
+struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *error_) {
+ static const struct dns_addrinfo ai_initializer;
+ struct dns_addrinfo *ai;
+ int error;
+
+ if (!res)
+ return 0;
+
+ dns_res_acquire(res);
+
+ if (!(ai = malloc(sizeof *ai)))
+ goto syerr;
+
+ *ai = ai_initializer;
+ ai->hints = *hints;
+
+ ai->res = res;
+ res = 0;
+
+ if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
+ { error = ENAMETOOLONG; goto error; }
+
+ ai->qtype = qtype;
+ ai->qport = 0;
+
+ if (serv) {
+ while (isdigit((unsigned char)*serv)) {
+ ai->qport *= 10;
+ ai->qport += *serv++ - '0';
+ }
+ }
+
+ ai->port = ai->qport;
+
+ return ai;
+syerr:
+ error = dns_syerr();
+error:
+ *error_ = error;
+
+ dns_ai_close(ai);
+ dns_res_close(res);
+
+ return 0;
+} /* dns_ai_open() */
+
+
+void dns_ai_close(struct dns_addrinfo *ai) {
+ if (!ai)
+ return;
+
+ dns_res_close(ai->res);
+
+ if (ai->answer != ai->glue)
+ free(ai->glue);
+
+ free(ai->answer);
+ free(ai);
+} /* dns_ai_close() */
+
+
+static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
+ struct sockaddr *saddr;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ const char *cname;
+ size_t clen;
+
+ switch (type) {
+ case DNS_T_A:
+ saddr = memset(&sin, '\0', sizeof sin);
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(ai->port);
+
+ memcpy(&sin.sin_addr, any, sizeof sin.sin_addr);
+
+ break;
+ case DNS_T_AAAA:
+ saddr = memset(&sin6, '\0', sizeof sin6);
+
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(ai->port);
+
+ memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr);
+
+ break;
+ default:
+ return EINVAL;
+ } /* switch() */
+
+ if (ai->hints.ai_flags & AI_CANONNAME) {
+ cname = (*ai->cname)? ai->cname : ai->qname;
+ clen = strlen(cname);
+ } else {
+ cname = NULL;
+ clen = 0;
+ }
+
+ if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
+ return dns_syerr();
+
+ memset(*ent, '\0', sizeof **ent);
+
+ (*ent)->ai_family = saddr->sa_family;
+ (*ent)->ai_socktype = ai->hints.ai_socktype;
+ (*ent)->ai_protocol = ai->hints.ai_protocol;
+
+ (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr));
+ (*ent)->ai_addrlen = dns_sa_len(saddr);
+
+ if (ai->hints.ai_flags & AI_CANONNAME)
+ (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1);
+
+ return 0;
+} /* dns_ai_setent() */
+
+
+enum dns_ai_state {
+ DNS_AI_S_INIT,
+ DNS_AI_S_NUMERIC,
+ DNS_AI_S_SUBMIT,
+ DNS_AI_S_CHECK,
+ DNS_AI_S_FETCH,
+ DNS_AI_S_FOREACH_I,
+ DNS_AI_S_FOREACH_G,
+ DNS_AI_S_SUBMIT_G,
+ DNS_AI_S_CHECK_G,
+ DNS_AI_S_FETCH_G,
+ DNS_AI_S_DONE,
+}; /* enum dns_ai_state */
+
+#define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
+
+int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
+ struct dns_packet *ans, *glue;
+ struct dns_rr rr;
+ char qname[DNS_D_MAXNAME + 1];
+ union dns_any any;
+ size_t len;
+ int error;
+
+ *ent = 0;
+
+exec:
+
+ switch (ai->state) {
+ case DNS_AI_S_INIT:
+ ai->state++;
+ case DNS_AI_S_NUMERIC:
+ if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
+ ai->state = DNS_AI_S_DONE;
+
+ return dns_ai_setent(ent, &any, DNS_T_A, ai);
+ }
+
+ if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
+ ai->state = DNS_AI_S_DONE;
+
+ return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
+ }
+
+ if (ai->hints.ai_flags & AI_NUMERICHOST)
+ dns_ai_goto(DNS_AI_S_DONE);
+
+ ai->state++;
+ case DNS_AI_S_SUBMIT:
+ if ((error = dns_res_submit(ai->res, ai->qname, ai->qtype, DNS_C_IN)))
+ return error;
+
+ ai->state++;
+ case DNS_AI_S_CHECK:
+ if ((error = dns_res_check(ai->res)))
+ return error;
+
+ ai->state++;
+ case DNS_AI_S_FETCH:
+ if (!(ai->answer = dns_res_fetch(ai->res, &error)))
+ return error;
+
+ if ((error = dns_p_study(ai->answer)))
+ return error;
+
+ ai->glue = ai->answer;
+
+ dns_rr_i_init(&ai->i, ai->answer);
+
+ ai->i.section = DNS_S_AN;
+ ai->i.type = ai->qtype;
+ ai->i.sort = &dns_rr_i_order;
+
+ ai->state++;
+ case DNS_AI_S_FOREACH_I:
+ /* Search generator may have changed our qname. */
+ if (!(len = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
+ return error;
+ else if (len >= sizeof qname)
+ return DNS_EILLEGAL;
+
+ if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, strlen(qname), ai->answer, &error))
+ return error;
+
+ ai->i.name = ai->cname;
+
+ if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
+ dns_ai_goto(DNS_AI_S_DONE);
+
+ if ((error = dns_any_parse(&any, &rr, ai->answer)))
+ return error;
+
+ ai->port = ai->qport;
+
+ switch (rr.type) {
+ case DNS_T_A:
+ case DNS_T_AAAA:
+ return dns_ai_setent(ent, &any, rr.type, ai);
+ default:
+ if (!dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type))
+ dns_ai_goto(DNS_AI_S_FOREACH_I);
+
+ /*
+ * Find the "real" canonical name. Some authorities
+ * publish aliases where an RFC defines a canonical
+ * name. We trust that the resolver followed any
+ * CNAME chains on it's own, regardless of whether
+ * the "smart" option is enabled.
+ */
+ if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->answer, &error))
+ return error;
+
+ if (rr.type == DNS_T_SRV)
+ ai->port = any.srv.port;
+
+ break;
+ } /* switch() */
+
+ dns_rr_i_init(&ai->g, ai->glue);
+
+ ai->g.section = DNS_S_ALL & ~DNS_S_QD;
+ ai->g.name = ai->cname;
+ ai->g.type = (ai->hints.ai_family == AF_INET6)? DNS_T_AAAA : DNS_T_A;
+
+ ai->state++;
+ case DNS_AI_S_FOREACH_G:
+ if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
+ if (dns_rr_i_count(&ai->g) > 0)
+ dns_ai_goto(DNS_AI_S_FOREACH_I);
+ else
+ dns_ai_goto(DNS_AI_S_SUBMIT_G);
+ }
+
+ if ((error = dns_any_parse(&any, &rr, ai->glue)))
+ return error;
+
+ return dns_ai_setent(ent, &any, rr.type, ai);
+ case DNS_AI_S_SUBMIT_G:
+ if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
+ dns_ai_goto(DNS_AI_S_FOREACH_I);
+
+ if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
+ return error;
+
+ ai->state++;
+ case DNS_AI_S_CHECK_G:
+ if ((error = dns_res_check(ai->res)))
+ return error;
+
+ ai->state++;
+ case DNS_AI_S_FETCH_G:
+ if (!(ans = dns_res_fetch(ai->res, &error)))
+ return error;
+
+ dns_p_study(ans);
+
+ glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
+
+ free(ans);
+
+ if (!glue)
+ return error;
+
+ if (ai->glue != ai->answer)
+ free(ai->glue);
+
+ ai->glue = glue;
+
+ dns_rr_i_init(&ai->g, ai->glue);
+
+ /* ai->g.name should already point to ai->cname */
+ if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->glue, &error))
+ dns_ai_goto(DNS_AI_S_FOREACH_I);
+
+ /* NOTE: Keep all the other iterator filters */
+
+ dns_ai_goto(DNS_AI_S_FOREACH_G);
+ case DNS_AI_S_DONE:
+ return ENOENT;
+ default:
+ return EINVAL;
+ } /* switch() */
+} /* dns_ai_nextent() */
+
+
+time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
+ return dns_res_elapsed(ai->res);
+} /* dns_ai_elapsed() */
+
+
+void dns_ai_clear(struct dns_addrinfo *ai) {
+ return dns_res_clear(ai->res);
+} /* dns_ai_clear() */
+
+
+int dns_ai_events(struct dns_addrinfo *ai) {
+ return dns_res_events(ai->res);
+} /* dns_ai_events() */
+
+
+int dns_ai_pollfd(struct dns_addrinfo *ai) {
+ return dns_res_pollfd(ai->res);
+} /* dns_ai_pollfd() */
+
+
+int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
+ return dns_res_poll(ai->res, timeout);
+} /* dns_ai_poll() */
+
+
+size_t dns_ai_print(void *dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
+ char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
+ size_t cp = 0;
+
+ cp += dns__printstring(dst, lim, cp, "[ ");
+ cp += dns__printstring(dst, lim, cp, ai->qname);
+ cp += dns__printstring(dst, lim, cp, " IN ");
+ cp += dns__printstring(dst, lim, cp, dns_strtype(ai->qtype));
+ cp += dns__printstring(dst, lim, cp, " ]\n");
+
+ cp += dns__printstring(dst, lim, cp, ".ai_family = ");
+
+ switch (ent->ai_family) {
+ case AF_INET:
+ cp += dns__printstring(dst, lim, cp, "AF_INET");
+ break;
+ case AF_INET6:
+ cp += dns__printstring(dst, lim, cp, "AF_INET6");
+ break;
+ default:
+ cp += dns__print10(dst, lim, cp, ent->ai_family, 0);
+ break;
+ }
+
+ cp += dns__printchar(dst, lim, cp, '\n');
+
+ cp += dns__printstring(dst, lim, cp, ".ai_socktype = ");
+
+ switch (ent->ai_socktype) {
+ case SOCK_STREAM:
+ cp += dns__printstring(dst, lim, cp, "SOCK_STREAM");
+ break;
+ case SOCK_DGRAM:
+ cp += dns__printstring(dst, lim, cp, "SOCK_DGRAM");
+ break;
+ default:
+ cp += dns__print10(dst, lim, cp, ent->ai_socktype, 0);
+ break;
+ }
+
+ cp += dns__printchar(dst, lim, cp, '\n');
+
+ cp += dns__printstring(dst, lim, cp, ".ai_addr = [");
+
+ dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), addr, sizeof addr);
+
+ cp += dns__printstring(dst, lim, cp, addr);
+ cp += dns__printstring(dst, lim, cp, "]:");
+
+ cp += dns__print10(dst, lim, cp, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
+ cp += dns__printchar(dst, lim, cp, '\n');
+
+ cp += dns__printstring(dst, lim, cp, ".ai_canonname = ");
+ cp += dns__printstring(dst, lim, cp, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
+ cp += dns__printchar(dst, lim, cp, '\n');
+
+ dns__printnul(dst, lim, cp);
+
+ return cp;
+} /* dns_ai_print() */
+
+
+const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
+ return dns_res_stat(ai->res);
+} /* dns_ai_stat() */
+
+
+/*
+ * M I S C E L L A N E O U S R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static const struct {
+ char name[16];
+ enum dns_section type;
+} dns_sections[] = {
+ { "QUESTION", DNS_S_QUESTION },
+ { "QD", DNS_S_QUESTION },
+ { "ANSWER", DNS_S_ANSWER },
+ { "AN", DNS_S_ANSWER },
+ { "AUTHORITY", DNS_S_AUTHORITY },
+ { "NS", DNS_S_AUTHORITY },
+ { "ADDITIONAL", DNS_S_ADDITIONAL },
+ { "AR", DNS_S_ADDITIONAL },
+};
+
+const char *(dns_strsection)(enum dns_section section, void *dst, size_t lim) {
+ unsigned i, p = 0;
+
+ for (i = 0; i < lengthof(dns_sections); i++) {
+ if (dns_sections[i].type & section) {
+ if (p > 0)
+ p += dns__printchar(dst, lim, p, '|');
+
+ p += dns__printstring(dst, lim, p, dns_sections[i].name);
+
+ section &= ~dns_sections[i].type;
+ }
+ }
+
+ if (!p)
+ p += dns__print10(dst, lim, 0, (0xffff & section), 0);
+
+ dns__printnul(dst, lim, p);
+
+ return dst;
+} /* dns_strsection() */
+
+
+enum dns_section dns_isection(const char *src) {
+ enum dns_section section = 0;
+ char sbuf[128];
+ char *name, *next;
+ unsigned i;
+
+ dns_strlcpy(sbuf, src, sizeof sbuf);
+ next = sbuf;
+
+ while ((name = dns_strsep(&next, "|+, \t"))) {
+ for (i = 0; i < lengthof(dns_sections); i++) {
+ if (!strcasecmp(dns_sections[i].name, name)) {
+ section |= dns_sections[i].type;
+ break;
+ }
+ }
+ }
+
+ return section;
+} /* dns_isection() */
+
+
+static const struct {
+ char name[8];
+ enum dns_class type;
+} dns_classes[] = {
+ { "IN", DNS_C_IN },
+};
+
+const char *(dns_strclass)(enum dns_class type, void *dst, size_t lim) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_classes); i++) {
+ if (dns_classes[i].type == type) {
+ dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_classes[i].name));
+
+ return dst;
+ }
+ }
+
+ dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0));
+
+ return dst;
+} /* dns_strclass() */
+
+
+enum dns_class dns_iclass(const char *name) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_classes); i++) {
+ if (!strcasecmp(dns_classes[i].name, name))
+ return dns_classes[i].type;
+ }
+
+ return 0;
+} /* dns_iclass() */
+
+
+const char *(dns_strtype)(enum dns_type type, void *dst, size_t lim) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (dns_rrtypes[i].type == type) {
+ dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_rrtypes[i].name));
+
+ return dst;
+ }
+ }
+
+ dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0));
+
+ return dst;
+} /* dns_strtype() */
+
+
+enum dns_type dns_itype(const char *type) {
+ unsigned i;
+
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (!strcasecmp(dns_rrtypes[i].name, type))
+ return dns_rrtypes[i].type;
+ }
+
+ return 0;
+} /* dns_itype() */
+
+
+static char dns_opcodes[16][16] = {
+ [DNS_OP_QUERY] = "QUERY",
+ [DNS_OP_IQUERY] = "IQUERY",
+ [DNS_OP_STATUS] = "STATUS",
+ [DNS_OP_NOTIFY] = "NOTIFY",
+ [DNS_OP_UPDATE] = "UPDATE",
+};
+
+const char *dns_stropcode(enum dns_opcode opcode) {
+ opcode &= 0xf;
+
+ if ('\0' == dns_opcodes[opcode][0])
+ dns__printnul(dns_opcodes[opcode], sizeof dns_opcodes[opcode], dns__print10(dns_opcodes[opcode], sizeof dns_opcodes[opcode], 0, opcode, 0));
+
+ return dns_opcodes[opcode];
+} /* dns_stropcode() */
+
+
+enum dns_opcode dns_iopcode(const char *name) {
+ unsigned opcode;
+
+ for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
+ if (!strcasecmp(name, dns_opcodes[opcode]))
+ return opcode;
+ }
+
+ return lengthof(dns_opcodes) - 1;
+} /* dns_iopcode() */
+
+
+static char dns_rcodes[16][16] = {
+ [DNS_RC_NOERROR] = "NOERROR",
+ [DNS_RC_FORMERR] = "FORMERR",
+ [DNS_RC_SERVFAIL] = "SERVFAIL",
+ [DNS_RC_NXDOMAIN] = "NXDOMAIN",
+ [DNS_RC_NOTIMP] = "NOTIMP",
+ [DNS_RC_REFUSED] = "REFUSED",
+ [DNS_RC_YXDOMAIN] = "YXDOMAIN",
+ [DNS_RC_YXRRSET] = "YXRRSET",
+ [DNS_RC_NXRRSET] = "NXRRSET",
+ [DNS_RC_NOTAUTH] = "NOTAUTH",
+ [DNS_RC_NOTZONE] = "NOTZONE",
+};
+
+const char *dns_strrcode(enum dns_rcode rcode) {
+ rcode &= 0xf;
+
+ if ('\0' == dns_rcodes[rcode][0])
+ dns__printnul(dns_rcodes[rcode], sizeof dns_rcodes[rcode], dns__print10(dns_rcodes[rcode], sizeof dns_rcodes[rcode], 0, rcode, 0));
+
+ return dns_rcodes[rcode];
+} /* dns_strrcode() */
+
+
+enum dns_rcode dns_ircode(const char *name) {
+ unsigned rcode;
+
+ for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
+ if (!strcasecmp(name, dns_rcodes[rcode]))
+ return rcode;
+ }
+
+ return lengthof(dns_rcodes) - 1;
+} /* dns_ircode() */
+
+
+/*
+ * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#if DNS_MAIN
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <ctype.h>
+
+#if _WIN32
+#include <getopt.h>
+#endif
+
+#if !_WIN32
+#include <err.h>
+#endif
+
+
+struct {
+ struct {
+ const char *path[8];
+ unsigned count;
+ } resconf;
+
+ struct {
+ const char *path[8];
+ unsigned count;
+ } hosts;
+
+ struct {
+ const char *path[8];
+ unsigned count;
+ } cache;
+
+ const char *qname;
+ enum dns_type qtype;
+
+ int (*sort)();
+
+ int verbose;
+} MAIN = {
+ .sort = &dns_rr_i_packet,
+};
+
+
+void hexdump(const unsigned char *src, size_t len, FILE *fp) {
+ static const unsigned char hex[] = "0123456789abcdef";
+ static const unsigned char tmpl[] = " | |\n";
+ unsigned char ln[sizeof tmpl];
+ const unsigned char *sp, *se;
+ unsigned char *h, *g;
+ unsigned i, n;
+
+ sp = src;
+ se = sp + len;
+
+ while (sp < se) {
+ memcpy(ln, tmpl, sizeof ln);
+
+ h = &ln[2];
+ g = &ln[53];
+
+ for (n = 0; n < 2; n++) {
+ for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
+ h[0] = hex[0x0f & (*sp >> 4)];
+ h[1] = hex[0x0f & (*sp >> 0)];
+ h += 3;
+
+ *g++ = (isgraph(*sp))? *sp : '.';
+ }
+
+ h++;
+ }
+
+ fputs((char *)ln, fp);
+ }
+
+ return /* void */;
+} /* hexdump() */
+
+
+static void panic(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+
+#if _WIN32
+ vfprintf(stderr, fmt, ap);
+
+ exit(EXIT_FAILURE);
+#else
+ verrx(EXIT_FAILURE, fmt, ap);
+#endif
+} /* panic() */
+
+#define panic_(fn, ln, fmt, ...) \
+ panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
+#define panic(...) \
+ panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
+
+
+static void *grow(unsigned char *p, size_t size) {
+ void *tmp;
+
+ if (!(tmp = realloc(p, size)))
+ panic("realloc(%zu): %s", size, dns_strerror(errno));
+
+ return tmp;
+} /* grow() */
+
+
+static size_t add(size_t a, size_t b) {
+ if (~a < b)
+ panic("%zu + %zu: integer overflow", a, b);
+
+ return a + b;
+} /* add() */
+
+
+static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
+ size_t size = add(osize, len);
+
+ *dst = grow(*dst, size);
+ memcpy(*dst + osize, src, len);
+
+ return size;
+} /* append() */
+
+
+static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
+ size_t size = osize;
+ unsigned char buf[1024];
+ size_t count;
+
+ while ((count = fread(buf, 1, sizeof buf, fp)))
+ size = append(dst, size, buf, count);
+
+ if (ferror(fp))
+ panic("%s: %s", path, dns_strerror(errno));
+
+ return size;
+} /* slurp() */
+
+
+static struct dns_resolv_conf *resconf(void) {
+ static struct dns_resolv_conf *resconf;
+ const char *path;
+ unsigned i;
+ int error;
+
+ if (resconf)
+ return resconf;
+
+ if (!(resconf = dns_resconf_open(&error)))
+ panic("dns_resconf_open: %s", dns_strerror(error));
+
+ if (!MAIN.resconf.count)
+ MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
+
+ for (i = 0; i < MAIN.resconf.count; i++) {
+ path = MAIN.resconf.path[i];
+
+ if (0 == strcmp(path, "-"))
+ error = dns_resconf_loadfile(resconf, stdin);
+ else
+ error = dns_resconf_loadpath(resconf, path);
+
+ if (error)
+ panic("%s: %s", path, dns_strerror(error));
+ }
+
+ return resconf;
+} /* resconf() */
+
+
+static struct dns_hosts *hosts(void) {
+ static struct dns_hosts *hosts;
+ const char *path;
+ unsigned i;
+ int error;
+
+ if (hosts)
+ return hosts;
+
+ if (!MAIN.hosts.count) {
+ MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
+
+ /* Explicitly test dns_hosts_local() */
+ if (!(hosts = dns_hosts_local(&error)))
+ panic("%s: %s", "/etc/hosts", dns_strerror(error));
+
+ return hosts;
+ }
+
+ if (!(hosts = dns_hosts_open(&error)))
+ panic("dns_hosts_open: %s", dns_strerror(error));
+
+ for (i = 0; i < MAIN.hosts.count; i++) {
+ path = MAIN.hosts.path[i];
+
+ if (0 == strcmp(path, "-"))
+ error = dns_hosts_loadfile(hosts, stdin);
+ else
+ error = dns_hosts_loadpath(hosts, path);
+
+ if (error)
+ panic("%s: %s", path, dns_strerror(error));
+ }
+
+ return hosts;
+} /* hosts() */
+
+
+#if DNS_CACHE
+#include "cache.h"
+
+struct dns_cache *cache(void) {
+ static struct cache *cache;
+ const char *path;
+ unsigned i;
+ int error;
+
+ if (cache)
+ return cache_resi(cache);
+ if (!MAIN.cache.count)
+ return NULL;
+
+ if (!(cache = cache_open(&error)))
+ panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
+
+ for (i = 0; i < MAIN.cache.count; i++) {
+ path = MAIN.cache.path[i];
+
+ if (!strcmp(path, "-")) {
+ if ((error = cache_loadfile(cache, stdin, NULL, 0)))
+ panic("%s: %s", path, dns_strerror(error));
+ } else if ((error = cache_loadpath(cache, path, NULL, 0)))
+ panic("%s: %s", path, dns_strerror(error));
+ }
+
+ return cache_resi(cache);
+} /* cache() */
+#else
+struct dns_cache *cache(void) { return NULL; }
+#endif
+
+
+static void print_packet(struct dns_packet *P, FILE *fp) {
+ dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
+
+ if (MAIN.verbose > 2)
+ hexdump(P->data, P->end, fp);
+} /* print_packet() */
+
+
+static int parse_packet(int argc, char *argv[]) {
+ struct dns_packet *P = dns_p_new(512);
+ struct dns_packet *Q = dns_p_new(512);
+ enum dns_section section;
+ struct dns_rr rr;
+ int error;
+ union dns_any any;
+ char pretty[sizeof any * 2];
+ size_t len;
+
+ P->end = fread(P->data, 1, P->size, stdin);
+
+ fputs(";; [HEADER]\n", stdout);
+ fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "QUERY" : "RESPONSE", dns_header(P)->qr);
+ fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode);
+ fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa);
+ fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc);
+ fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd);
+ fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra);
+ fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode);
+
+ section = 0;
+
+ dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
+ if (section != rr.section)
+ fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
+
+ if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
+ fprintf(stdout, "%s\n", pretty);
+
+ dns_rr_copy(Q, &rr, P);
+
+ section = rr.section;
+ }
+
+ fputs("; ; ; ; ; ; ; ;\n\n", stdout);
+
+ section = 0;
+
+#if 0
+ dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
+#else
+ struct dns_rr rrset[32];
+ struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
+ unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
+ unsigned i;
+
+ for (i = 0; i < rrcount; i++) {
+ rr = rrset[i];
+#endif
+ if (section != rr.section)
+ fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
+
+ if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
+ fprintf(stdout, "%s\n", pretty);
+
+ section = rr.section;
+ }
+
+ if (MAIN.verbose > 1) {
+ fprintf(stderr, "orig:%zu\n", P->end);
+ hexdump(P->data, P->end, stdout);
+
+ fprintf(stderr, "copy:%zu\n", Q->end);
+ hexdump(Q->data, Q->end, stdout);
+ }
+
+ return 0;
+} /* parse_packet() */
+
+
+static int parse_domain(int argc, char *argv[]) {
+ char *dn;
+
+ dn = (argc > 1)? argv[1] : "f.l.google.com";
+
+ printf("[%s]\n", dn);
+
+ dn = dns_d_new(dn);
+
+ do {
+ puts(dn);
+ } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
+
+ return 0;
+} /* parse_domain() */
+
+
+static int expand_domain(int argc, char *argv[]) {
+ unsigned short rp = 0;
+ unsigned char *src = NULL;
+ unsigned char *dst;
+ struct dns_packet *pkt;
+ size_t lim = 0, len;
+ int error;
+
+ if (argv[1])
+ rp = atoi(argv[1]);
+
+ len = slurp(&src, 0, stdin, "-");
+
+ if (!(pkt = dns_p_make(len, &error)))
+ panic("malloc(%zu): %s", len, dns_strerror(error));
+
+ memcpy(pkt->data, src, len);
+ pkt->end = len;
+
+ lim = 1;
+ dst = grow(NULL, lim);
+
+ while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
+ lim = add(len, 1);
+ dst = grow(dst, lim);
+ }
+
+ if (!len)
+ panic("expand: %s", dns_strerror(error));
+
+ fwrite(dst, 1, len, stdout);
+ fflush(stdout);
+
+ free(src);
+ free(dst);
+ free(pkt);
+
+ return 0;
+} /* expand_domain() */
+
+
+static int show_resconf(int argc, char *argv[]) {
+ unsigned i;
+
+ resconf(); /* load it */
+
+ fputs("; SOURCES\n", stdout);
+
+ for (i = 0; i < MAIN.resconf.count; i++)
+ fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
+
+ fputs(";\n", stdout);
+
+ dns_resconf_dump(resconf(), stdout);
+
+ return 0;
+} /* show_resconf() */
+
+
+static int show_hosts(int argc, char *argv[]) {
+ unsigned i;
+
+ hosts();
+
+ fputs("# SOURCES\n", stdout);
+
+ for (i = 0; i < MAIN.hosts.count; i++)
+ fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
+
+ fputs("#\n", stdout);
+
+ dns_hosts_dump(hosts(), stdout);
+
+ return 0;
+} /* show_hosts() */
+
+
+static int query_hosts(int argc, char *argv[]) {
+ struct dns_packet *Q = dns_p_new(512);
+ struct dns_packet *A;
+ char qname[DNS_D_MAXNAME + 1];
+ size_t qlen;
+ int error;
+
+ if (!MAIN.qname)
+ MAIN.qname = (argc > 1)? argv[1] : "localhost";
+ if (!MAIN.qtype)
+ MAIN.qtype = DNS_T_A;
+
+ hosts();
+
+ if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
+ union { struct in_addr a; struct in6_addr a6; } addr;
+ int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
+
+ if (1 != dns_inet_pton(af, MAIN.qname, &addr))
+ panic("%s: %s", MAIN.qname, dns_strerror(error));
+
+ qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
+ } else
+ qlen = dns__printstring(qname, sizeof qname, 0, MAIN.qname);
+
+ if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
+ panic("%s: %s", qname, dns_strerror(error));
+
+ if (!(A = dns_hosts_query(hosts(), Q, &error)))
+ panic("%s: %s", qname, dns_strerror(error));
+
+ print_packet(A, stdout);
+
+ free(A);
+
+ return 0;
+} /* query_hosts() */
+
+
+static int search_list(int argc, char *argv[]) {
+ const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
+ unsigned long i = 0;
+ char name[DNS_D_MAXNAME + 1];
+
+ printf("[%s]\n", qname);
+
+ while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
+ puts(name);
+
+ return 0;
+} /* search_list() */
+
+
+int permute_set(int argc, char *argv[]) {
+ unsigned lo, hi, i;
+ struct dns_k_permutor p;
+
+ hi = (--argc > 0)? atoi(argv[argc]) : 8;
+ lo = (--argc > 0)? atoi(argv[argc]) : 0;
+
+ fprintf(stderr, "[%u .. %u]\n", lo, hi);
+
+ dns_k_permutor_init(&p, lo, hi);
+
+ for (i = lo; i <= hi; i++)
+ fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
+// printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
+
+ return 0;
+} /* permute_set() */
+
+
+int shuffle_16(int argc, char *argv[]) {
+ unsigned n, r;
+
+ if (--argc > 0) {
+ n = 0xffff & atoi(argv[argc]);
+ r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
+
+ fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
+ } else {
+ r = dns_random();
+
+ for (n = 0; n < 65536; n++)
+ fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
+ }
+
+ return 0;
+} /* shuffle_16() */
+
+
+int dump_random(int argc, char *argv[]) {
+ unsigned char b[32];
+ unsigned i, j, n, r;
+
+ n = (argc > 1)? atoi(argv[1]) : 32;
+
+ while (n) {
+ i = 0;
+
+ do {
+ r = dns_random();
+
+ for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
+ b[i] = 0xff & r;
+ r >>= 8;
+ }
+ } while (i < n && i < sizeof b);
+
+ hexdump(b, i, stdout);
+
+ n -= i;
+ }
+
+ return 0;
+} /* dump_random() */
+
+
+static int send_query(int argc, char *argv[]) {
+ struct dns_packet *A, *Q = dns_p_new(512);
+ char host[INET6_ADDRSTRLEN + 1];
+ struct sockaddr_storage ss;
+ struct dns_socket *so;
+ int error, type;
+
+ if (argc > 1) {
+ ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
+
+ if (1 != dns_inet_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss)))
+ panic("%s: invalid host address", argv[1]);
+
+ *dns_sa_port(ss.ss_family, &ss) = htons(53);
+ } else
+ memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
+
+ if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss), host, sizeof host))
+ panic("bad host address, or none provided");
+
+ if (!MAIN.qname)
+ MAIN.qname = "ipv6.google.com";
+ if (!MAIN.qtype)
+ MAIN.qtype = DNS_T_AAAA;
+
+ if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
+ panic("dns_p_push: %s", dns_strerror(error));
+
+ dns_header(Q)->rd = 1;
+
+ if (strstr(argv[0], "udp"))
+ type = SOCK_DGRAM;
+ else if (strstr(argv[0], "tcp"))
+ type = SOCK_STREAM;
+ else
+ type = dns_res_tcp2type(resconf()->options.tcp);
+
+ fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
+
+ if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
+ panic("dns_so_open: %s", dns_strerror(error));
+
+ while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
+ if (error != EAGAIN)
+ panic("dns_so_query: %s (%d)", dns_strerror(error), error);
+ if (dns_so_elapsed(so) > 10)
+ panic("query timed-out");
+
+ dns_so_poll(so, 1);
+ }
+
+ print_packet(A, stdout);
+
+ dns_so_close(so);
+
+ return 0;
+} /* send_query() */
+
+
+static int print_arpa(int argc, char *argv[]) {
+ const char *ip = (argc > 1)? argv[1] : "::1";
+ int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
+ union { struct in_addr a4; struct in6_addr a6; } addr;
+ char host[DNS_D_MAXNAME + 1];
+
+ if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
+ panic("%s: invalid address", ip);
+
+ fprintf(stdout, "%s\n", host);
+
+ return 0;
+} /* print_arpa() */
+
+
+static int show_hints(int argc, char *argv[]) {
+ struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
+ const char *which, *how, *who;
+ struct dns_hints *hints;
+ int error;
+
+ which = (argc > 1)? argv[1] : "local";
+ how = (argc > 2)? argv[2] : "plain";
+ who = (argc > 3)? argv[3] : "google.com";
+
+ load = (0 == strcmp(which, "local"))
+ ? &dns_hints_local
+ : &dns_hints_root;
+
+ if (!(hints = load(resconf(), &error)))
+ panic("%s: %s", argv[0], dns_strerror(error));
+
+ if (0 == strcmp(how, "plain")) {
+ dns_hints_dump(hints, stdout);
+ } else {
+ struct dns_packet *query, *answer;
+
+ query = dns_p_new(512);
+
+ if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
+ panic("%s: %s", who, dns_strerror(error));
+
+ if (!(answer = dns_hints_query(hints, query, &error)))
+ panic("%s: %s", who, dns_strerror(error));
+
+ print_packet(answer, stdout);
+
+ free(answer);
+ }
+
+ dns_hints_close(hints);
+
+ return 0;
+} /* show_hints() */
+
+
+static int resolve_query(int argc, char *argv[]) {
+ struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local;
+ struct dns_resolver *R;
+ struct dns_packet *ans;
+ const struct dns_stat *st;
+ int error;
+
+ if (!MAIN.qname)
+ MAIN.qname = "www.google.com";
+ if (!MAIN.qtype)
+ MAIN.qtype = DNS_T_A;
+
+ resconf()->options.recurse = (0 != strstr(argv[0], "recurse"));
+
+ if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
+ panic("%s: %s", MAIN.qname, dns_strerror(error));
+
+ if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
+ panic("%s: %s", MAIN.qname, dns_strerror(error));
+
+ while ((error = dns_res_check(R))) {
+ if (error != EAGAIN)
+ panic("dns_res_check: %s (%d)", dns_strerror(error), error);
+ if (dns_res_elapsed(R) > 30)
+ panic("query timed-out");
+
+ dns_res_poll(R, 1);
+ }
+
+ ans = dns_res_fetch(R, &error);
+ print_packet(ans, stdout);
+ free(ans);
+
+ st = dns_res_stat(R);
+ putchar('\n');
+ printf(";; queries: %zu\n", st->queries);
+ printf(";; udp sent: %zu in %zu bytes\n", st->udp.sent.count, st->udp.sent.bytes);
+ printf(";; udp rcvd: %zu in %zu bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
+ printf(";; tcp sent: %zu in %zu bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
+ printf(";; tcp rcvd: %zu in %zu bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
+
+ dns_res_close(R);
+
+ return 0;
+} /* resolve_query() */
+
+
+static int resolve_addrinfo(int argc, char *argv[]) {
+ struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local;
+ struct dns_resolver *res = 0;
+ struct dns_addrinfo *ai = 0;
+ struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
+ struct addrinfo *ent;
+ char pretty[512];
+ int error;
+
+ if (!MAIN.qname)
+ MAIN.qname = "www.google.com";
+ if (!MAIN.qtype)
+ MAIN.qtype = DNS_T_A;
+
+ resconf()->options.recurse = (0 != strstr(argv[0], "recurse"));
+
+ if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
+ panic("%s: %s", MAIN.qname, dns_strerror(error));
+
+ if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
+ panic("%s: %s", MAIN.qname, dns_strerror(error));
+
+ do {
+ switch (error = dns_ai_nextent(&ent, ai)) {
+ case 0:
+ dns_ai_print(pretty, sizeof pretty, ent, ai);
+
+ fputs(pretty, stdout);
+
+ free(ent);
+
+ break;
+ case ENOENT:
+ break;
+ case EAGAIN:
+ if (dns_ai_elapsed(ai) > 30)
+ panic("query timed-out");
+
+ dns_ai_poll(ai, 1);
+
+ break;
+ default:
+ panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
+ }
+ } while (error != ENOENT);
+
+ dns_res_close(res);
+ dns_ai_close(ai);
+
+ return 0;
+} /* resolve_addrinfo() */
+
+
+static int echo_port(int argc, char *argv[]) {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ } port;
+ int fd;
+
+ memset(&port, 0, sizeof port);
+ port.sin.sin_family = AF_INET;
+ port.sin.sin_port = htons(5354);
+ port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
+ panic("socket: %s", strerror(errno));
+
+ if (0 != bind(fd, &port.sa, sizeof port.sa))
+ panic("127.0.0.1:5353: %s", dns_strerror(errno));
+
+ for (;;) {
+ struct dns_packet *pkt = dns_p_new(512);
+ struct sockaddr_storage ss;
+ socklen_t slen = sizeof ss;
+ ssize_t count;
+#if defined(MSG_WAITALL) /* MinGW issue */
+ int rflags = MSG_WAITALL;
+#else
+ int rflags = 0;
+#endif
+
+ count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
+
+
+ if (!count || count < 0)
+ panic("recvfrom: %s", strerror(errno));
+
+ pkt->end = count;
+
+ dns_p_dump(pkt, stdout);
+
+ (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
+ }
+
+ return 0;
+} /* echo_port() */
+
+
+static int isection(int argc, char *argv[]) {
+ const char *name = (argv[1])? argv[1] : "";
+ int type;
+
+ type = dns_isection(name);
+ name = dns_strsection(type);
+
+ printf("%s (%d)\n", name, type);
+
+ return 0;
+} /* isection() */
+
+
+static int iclass(int argc, char *argv[]) {
+ const char *name = (argv[1])? argv[1] : "";
+ int type;
+
+ type = dns_iclass(name);
+ name = dns_strclass(type);
+
+ printf("%s (%d)\n", name, type);
+
+ return 0;
+} /* iclass() */
+
+
+static int itype(int argc, char *argv[]) {
+ const char *name = (argv[1])? argv[1] : "";
+ int type;
+
+ type = dns_itype(name);
+ name = dns_strtype(type);
+
+ printf("%s (%d)\n", name, type);
+
+ return 0;
+} /* itype() */
+
+
+static int iopcode(int argc, char *argv[]) {
+ const char *name = (argv[1])? argv[1] : "";
+ int type;
+
+ type = dns_iopcode(name);
+ name = dns_stropcode(type);
+
+ printf("%s (%d)\n", name, type);
+
+ return 0;
+} /* iopcode() */
+
+
+static int ircode(int argc, char *argv[]) {
+ const char *name = (argv[1])? argv[1] : "";
+ int type;
+
+ type = dns_ircode(name);
+ name = dns_strrcode(type);
+
+ printf("%s (%d)\n", name, type);
+
+ return 0;
+} /* ircode() */
+
+
+#define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
+#define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
+#define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
+#define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
+#define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+static int sizes(int argc, char *argv[]) {
+ static const struct { const char *name; size_t size; } type[] = {
+ SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
+ SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
+ SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
+ SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
+ SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
+ SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
+ SIZE(struct dns_cache),
+ };
+ unsigned i, max;
+
+ for (i = 0, max = 0; i < lengthof(type); i++)
+ max = MAX(max, strlen(type[i].name));
+
+ for (i = 0; i < lengthof(type); i++)
+ printf("%*s : %zu\n", max, type[i].name, type[i].size);
+
+ return 0;
+} /* sizes() */
+
+
+static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
+ { "parse-packet", &parse_packet, "parse binary packet from stdin" },
+ { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
+ { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
+ { "show-resconf", &show_resconf, "show resolv.conf data" },
+ { "show-hosts", &show_hosts, "show hosts data" },
+ { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
+ { "search-list", &search_list, "generate query search list from domain" },
+ { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
+ { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
+ { "dump-random", &dump_random, "generate random bytes" },
+ { "send-query", &send_query, "send query to host" },
+ { "send-query-udp", &send_query, "send udp query to host" },
+ { "send-query-tcp", &send_query, "send tcp query to host" },
+ { "print-arpa", &print_arpa, "print arpa. zone name of address" },
+ { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
+ { "resolve-stub", &resolve_query, "resolve as stub resolver" },
+ { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
+ { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
+ { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
+/* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
+ { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
+ { "isection", &isection, "parse section string" },
+ { "iclass", &iclass, "parse class string" },
+ { "itype", &itype, "parse type string" },
+ { "iopcode", &iopcode, "parse opcode string" },
+ { "ircode", &ircode, "parse rcode string" },
+ { "sizes", &sizes, "print data structure sizes" },
+};
+
+
+static void print_usage(const char *progname, FILE *fp) {
+ static const char *usage =
+ " [OPTIONS] COMMAND [ARGS]\n"
+ " -c PATH Path to resolv.conf\n"
+ " -l PATH Path to local hosts\n"
+ " -z PATH Path to zone cache\n"
+ " -q QNAME Query name\n"
+ " -t QTYPE Query type\n"
+ " -s HOW Sort records\n"
+ " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
+ " -V Print version info\n"
+ " -h Print this usage message\n"
+ "\n";
+ unsigned i, n, m;
+
+ fputs(progname, fp);
+ fputs(usage, fp);
+
+ for (i = 0, m = 0; i < lengthof(cmds); i++) {
+ if (strlen(cmds[i].cmd) > m)
+ m = strlen(cmds[i].cmd);
+ }
+
+ for (i = 0; i < lengthof(cmds); i++) {
+ fprintf(fp, " %s ", cmds[i].cmd);
+
+ for (n = strlen(cmds[i].cmd); n < m; n++)
+ putc(' ', fp);
+
+ fputs(cmds[i].help, fp);
+ putc('\n', fp);
+ }
+
+ fputs("\nReport bugs to William Ahern <william@25thandClement.com>\n", fp);
+} /* print_usage() */
+
+
+static void print_version(const char *progname, FILE *fp) {
+ fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
+ fprintf(fp, "vendor %s\n", dns_vendor());
+ fprintf(fp, "release %.8X\n", dns_v_rel());
+ fprintf(fp, "abi %.8X\n", dns_v_abi());
+ fprintf(fp, "api %.8X\n", dns_v_api());
+} /* print_version() */
+
+
+int main(int argc, char **argv) {
+ extern int optind;
+ extern char *optarg;
+ const char *progname = argv[0];
+ unsigned i;
+ int ch;
+
+ while (-1 != (ch = getopt(argc, argv, "q:t:c:l:z:s:vVh"))) {
+ switch (ch) {
+ case 'c':
+ assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
+
+ MAIN.resconf.path[MAIN.resconf.count++] = optarg;
+
+ break;
+ case 'l':
+ assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
+
+ MAIN.hosts.path[MAIN.hosts.count++] = optarg;
+
+ break;
+ case 'z':
+ assert(MAIN.cache.count < lengthof(MAIN.cache.path));
+
+ MAIN.cache.path[MAIN.cache.count++] = optarg;
+
+ break;
+ case 'q':
+ MAIN.qname = optarg;
+
+ break;
+ case 't':
+ for (i = 0; i < lengthof(dns_rrtypes); i++) {
+ if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
+ { MAIN.qtype = dns_rrtypes[i].type; break; }
+ }
+
+ if (MAIN.qtype)
+ break;
+
+ for (i = 0; isdigit((int)optarg[i]); i++) {
+ MAIN.qtype *= 10;
+ MAIN.qtype += optarg[i] - '0';
+ }
+
+ if (!MAIN.qtype)
+ panic("%s: invalid query type", optarg);
+
+ break;
+ case 's':
+ if (0 == strcasecmp(optarg, "packet"))
+ MAIN.sort = &dns_rr_i_packet;
+ else if (0 == strcasecmp(optarg, "shuffle"))
+ MAIN.sort = &dns_rr_i_shuffle;
+ else if (0 == strcasecmp(optarg, "order"))
+ MAIN.sort = &dns_rr_i_order;
+ else
+ panic("%s: invalid sort method", optarg);
+
+ break;
+ case 'v':
+ dns_debug = ++MAIN.verbose;
+
+ break;
+ case 'V':
+ print_version(progname, stdout);
+
+ return 0;
+ case 'h':
+ print_usage(progname, stdout);
+
+ return 0;
+ default:
+ print_usage(progname, stderr);
+
+ return EXIT_FAILURE;
+ } /* switch() */
+ } /* while() */
+
+ argc -= optind;
+ argv += optind;
+
+ for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
+ if (0 == strcmp(cmds[i].cmd, argv[0]))
+ return cmds[i].run(argc, argv);
+ }
+
+ print_usage(progname, stderr);
+
+ return EXIT_FAILURE;
+} /* main() */
+
+
+#endif /* DNS_MAIN */
diff --git a/src/lib/ecore_con/dns.h b/src/lib/ecore_con/dns.h
new file mode 100644
index 0000000000..f9213167e5
--- /dev/null
+++ b/src/lib/ecore_con/dns.h
@@ -0,0 +1,1076 @@
+/* ==========================================================================
+ * dns.h - Recursive, Reentrant DNS Resolver.
+ * --------------------------------------------------------------------------
+ * Copyright (c) 2009, 2010 William Ahern
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ==========================================================================
+ */
+#ifndef DNS_H
+#define DNS_H
+
+#include <stddef.h> /* size_t offsetof() */
+#include <stdio.h> /* FILE */
+
+#include <string.h> /* strlen(3) */
+
+#include <time.h> /* time_t */
+
+#if _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h> /* socklen_t */
+#include <sys/socket.h> /* struct socket */
+
+#include <poll.h> /* POLLIN POLLOUT */
+
+#include <netinet/in.h> /* struct in_addr struct in6_addr */
+
+#include <netdb.h> /* struct addrinfo */
+#endif
+
+#include <Eina.h> /* EINA_UNUSED */
+
+
+/*
+ * V E R S I O N
+ *
+ * Vendor: Entity for which versions numbers are relevant. (If forking
+ * change DNS_VENDOR to avoid confusion.)
+ *
+ * Three versions:
+ *
+ * REL Official "release"--bug fixes, new features, etc.
+ * ABI Changes to existing object sizes or parameter types.
+ * API Changes that might effect application source.
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define DNS_VENDOR "william@25thandClement.com"
+
+#define DNS_V_REL 0x20110117
+#define DNS_V_ABI 0x20100709
+#define DNS_V_API 0x20100709
+
+
+const char *dns_vendor(void);
+
+int dns_v_rel(void);
+int dns_v_abi(void);
+int dns_v_api(void);
+
+
+/*
+ * E R R O R S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+enum dns_errno {
+ DNS_ENOBUFS = -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64),
+ DNS_EILLEGAL,
+ DNS_EORDER,
+ DNS_ESECTION,
+ DNS_EUNKNOWN,
+}; /* dns_errno */
+
+const char *dns_strerror(int);
+
+extern int dns_debug;
+
+
+/*
+ * E V E N T S I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if defined(POLLIN)
+#define DNS_POLLIN POLLIN
+#else
+#define DNS_POLLIN 1
+#endif
+
+#if defined(POLLOUT)
+#define DNS_POLLOUT POLLOUT
+#else
+#define DNS_POLLOUT 2
+#endif
+
+
+/*
+ * See Application Interface below for configuring libevent bitmasks instead
+ * of poll(2) bitmasks.
+ */
+#define DNS_EVREAD 2
+#define DNS_EVWRITE 4
+
+
+#define DNS_POLL2EV(set) \
+ (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0)
+
+#define DNS_EV2POLL(set) \
+ (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0)
+
+
+/*
+ * E N U M E R A T I O N I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+enum dns_section {
+ DNS_S_QD = 0x01,
+#define DNS_S_QUESTION DNS_S_QD
+
+ DNS_S_AN = 0x02,
+#define DNS_S_ANSWER DNS_S_AN
+
+ DNS_S_NS = 0x04,
+#define DNS_S_AUTHORITY DNS_S_NS
+
+ DNS_S_AR = 0x08,
+#define DNS_S_ADDITIONAL DNS_S_AR
+
+ DNS_S_ALL = 0x0f
+}; /* enum dns_section */
+
+
+enum dns_class {
+ DNS_C_IN = 1,
+
+ DNS_C_ANY = 255
+}; /* enum dns_class */
+
+
+enum dns_type {
+ DNS_T_A = 1,
+ DNS_T_NS = 2,
+ DNS_T_CNAME = 5,
+ DNS_T_SOA = 6,
+ DNS_T_PTR = 12,
+ DNS_T_MX = 15,
+ DNS_T_TXT = 16,
+ DNS_T_AAAA = 28,
+ DNS_T_SRV = 33,
+ DNS_T_SSHFP = 44,
+ DNS_T_SPF = 99,
+
+ DNS_T_ALL = 255
+}; /* enum dns_type */
+
+
+enum dns_opcode {
+ DNS_OP_QUERY = 0,
+ DNS_OP_IQUERY = 1,
+ DNS_OP_STATUS = 2,
+ DNS_OP_NOTIFY = 4,
+ DNS_OP_UPDATE = 5,
+}; /* dns_opcode */
+
+
+enum dns_rcode {
+ DNS_RC_NOERROR = 0,
+ DNS_RC_FORMERR = 1,
+ DNS_RC_SERVFAIL = 2,
+ DNS_RC_NXDOMAIN = 3,
+ DNS_RC_NOTIMP = 4,
+ DNS_RC_REFUSED = 5,
+ DNS_RC_YXDOMAIN = 6,
+ DNS_RC_YXRRSET = 7,
+ DNS_RC_NXRRSET = 8,
+ DNS_RC_NOTAUTH = 9,
+ DNS_RC_NOTZONE = 10,
+}; /* dns_rcode */
+
+
+/*
+ * NOTE: These string functions need a small buffer in case the literal
+ * integer value needs to be printed and returned. UNLESS this buffer is
+ * SPECIFIED, the returned string has ONLY BLOCK SCOPE.
+ */
+#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */
+
+const char *dns_strsection(enum dns_section, void *, size_t);
+#define dns_strsection3(a, b, c) \
+ dns_strsection((a), (b), (c))
+#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
+#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+enum dns_section dns_isection(const char *);
+
+const char *dns_strclass(enum dns_class, void *, size_t);
+#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c))
+#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
+#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+enum dns_class dns_iclass(const char *);
+
+const char *dns_strtype(enum dns_type, void *, size_t);
+#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c))
+#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
+#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+enum dns_type dns_itype(const char *);
+
+const char *dns_stropcode(enum dns_opcode);
+
+enum dns_opcode dns_iopcode(const char *);
+
+const char *dns_strrcode(enum dns_rcode);
+
+enum dns_rcode dns_ircode(const char *);
+
+
+/*
+ * A T O M I C I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+typedef unsigned long dns_atomic_t;
+
+
+/*
+ * C R Y P T O I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+extern unsigned (*dns_random)(void);
+
+
+/*
+ * P A C K E T I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_header {
+ unsigned qid:16;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned qr:1;
+ unsigned opcode:4;
+ unsigned aa:1;
+ unsigned tc:1;
+ unsigned rd:1;
+
+ unsigned ra:1;
+ unsigned unused:3;
+ unsigned rcode:4;
+#else
+ unsigned rd:1;
+ unsigned tc:1;
+ unsigned aa:1;
+ unsigned opcode:4;
+ unsigned qr:1;
+
+ unsigned rcode:4;
+ unsigned unused:3;
+ unsigned ra:1;
+#endif
+
+ unsigned qdcount:16;
+ unsigned ancount:16;
+ unsigned nscount:16;
+ unsigned arcount:16;
+}; /* struct dns_header */
+
+#define dns_header(p) (&(p)->header)
+
+
+#ifndef DNS_P_QBUFSIZ
+#define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4)
+#endif
+
+#ifndef DNS_P_DICTSIZE
+#define DNS_P_DICTSIZE 16
+#endif
+
+struct dns_packet {
+ unsigned short dict[DNS_P_DICTSIZE];
+
+ struct dns_s_memo {
+ unsigned short base, end;
+ } qd, an, ns, ar;
+
+ struct { struct dns_packet *cqe_next, *cqe_prev; } cqe;
+
+ size_t size, end;
+
+ int:16; /* tcp padding */
+
+ union {
+ struct dns_header header;
+ unsigned char data[1];
+ };
+}; /* struct dns_packet */
+
+#define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n)))
+
+#define dns_p_sizeof(P) dns_p_calcsize((P)->end)
+
+/** takes size of maximum desired payload */
+#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n))))
+
+/** takes size of entire packet structure as allocated */
+struct dns_packet *dns_p_init(struct dns_packet *, size_t);
+
+/** takes size of maximum desired payload */
+struct dns_packet *dns_p_make(size_t, int *);
+
+int dns_p_grow(struct dns_packet **);
+
+struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *);
+
+#define dns_p_opcode(P) (dns_header(P)->opcode)
+
+#define dns_p_rcode(P) (dns_header(P)->rcode)
+
+unsigned dns_p_count(struct dns_packet *, enum dns_section);
+
+int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *);
+
+void dns_p_dictadd(struct dns_packet *, unsigned short);
+
+struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *);
+
+void dns_p_dump(struct dns_packet *, FILE *);
+
+int dns_p_study(struct dns_packet *);
+
+
+/*
+ * D O M A I N N A M E I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define DNS_D_MAXLABEL 63 /* + 1 '\0' */
+#define DNS_D_MAXNAME 255 /* + 1 '\0' */
+
+#define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */
+#define DNS_D_CLEAVE 2 /* cleave sub-domain */
+#define DNS_D_TRIM 4 /* remove superfluous dots */
+
+#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f))
+#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f))
+#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR)
+#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+
+char *dns_d_init(void *, size_t, const void *, size_t, int);
+
+size_t dns_d_anchor(void *, size_t, const void *, size_t);
+
+size_t dns_d_cleave(void *, size_t, const void *, size_t);
+
+size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *);
+
+size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *);
+
+unsigned short dns_d_skip(unsigned short, struct dns_packet *);
+
+int dns_d_push(struct dns_packet *, const void *, size_t);
+
+size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error);
+
+
+/*
+ * R E S O U R C E R E C O R D I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_rr {
+ enum dns_section section;
+
+ struct {
+ unsigned short p;
+ unsigned short len;
+ } dn;
+
+ enum dns_type type;
+ enum dns_class class;
+ unsigned ttl;
+
+ struct {
+ unsigned short p;
+ unsigned short len;
+ } rd;
+}; /* struct dns_rr */
+
+
+int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *);
+
+int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *);
+
+unsigned short dns_rr_skip(unsigned short, struct dns_packet *);
+
+int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *);
+
+size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *);
+
+
+#define dns_rr_i_new(P, ...) dns_rr_i_init(&(struct dns_rr_i){ 0, __VA_ARGS__ }, (P))
+
+struct dns_rr_i {
+ enum dns_section section;
+ const void *name;
+ enum dns_type type;
+ enum dns_class class;
+ const void *data;
+
+ int follow;
+
+ int (*sort)();
+ unsigned args[2];
+
+ struct {
+ unsigned short next;
+ unsigned short count;
+
+ unsigned exec;
+ unsigned regs[2];
+ } state, saved;
+}; /* struct dns_rr_i */
+
+int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
+
+int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
+
+int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
+
+struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *);
+
+#define dns_rr_i_save(i) ((i)->saved = (i)->state)
+#define dns_rr_i_rewind(i) ((i)->state = (i)->saved)
+#define dns_rr_i_count(i) ((i)->state.count)
+
+unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *);
+
+#define dns_rr_foreach_(rr, P, ...) \
+ for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); )
+
+#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__)
+
+
+/*
+ * A R E S O U R C E R E C O R D
+ */
+
+struct dns_a {
+ struct in_addr addr;
+}; /* struct dns_a */
+
+int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *);
+
+int dns_a_push(struct dns_packet *, struct dns_a *);
+
+int dns_a_cmp(const struct dns_a *, const struct dns_a *);
+
+size_t dns_a_print(void *, size_t, struct dns_a *);
+
+
+/*
+ * AAAA R E S O U R C E R E C O R D
+ */
+
+struct dns_aaaa {
+ struct in6_addr addr;
+}; /* struct dns_aaaa */
+
+int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *);
+
+int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *);
+
+int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *);
+
+size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *);
+
+
+/*
+ * MX R E S O U R C E R E C O R D
+ */
+
+struct dns_mx {
+ unsigned short preference;
+ char host[DNS_D_MAXNAME + 1];
+}; /* struct dns_mx */
+
+int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *);
+
+int dns_mx_push(struct dns_packet *, struct dns_mx *);
+
+int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *);
+
+size_t dns_mx_print(void *, size_t, struct dns_mx *);
+
+size_t dns_mx_cname(void *, size_t, struct dns_mx *);
+
+
+/*
+ * NS R E S O U R C E R E C O R D
+ */
+
+struct dns_ns {
+ char host[DNS_D_MAXNAME + 1];
+}; /* struct dns_ns */
+
+int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *);
+
+int dns_ns_push(struct dns_packet *, struct dns_ns *);
+
+int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *);
+
+size_t dns_ns_print(void *, size_t, struct dns_ns *);
+
+size_t dns_ns_cname(void *, size_t, struct dns_ns *);
+
+
+/*
+ * CNAME R E S O U R C E R E C O R D
+ */
+
+struct dns_cname {
+ char host[DNS_D_MAXNAME + 1];
+}; /* struct dns_cname */
+
+int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *);
+
+int dns_cname_push(struct dns_packet *, struct dns_cname *);
+
+int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *);
+
+size_t dns_cname_print(void *, size_t, struct dns_cname *);
+
+size_t dns_cname_cname(void *, size_t, struct dns_cname *);
+
+
+/*
+ * SOA R E S O U R C E R E C O R D
+ */
+
+struct dns_soa {
+ char mname[DNS_D_MAXNAME + 1];
+ char rname[DNS_D_MAXNAME + 1];
+ unsigned serial, refresh, retry, expire, minimum;
+}; /* struct dns_soa */
+
+int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *);
+
+int dns_soa_push(struct dns_packet *, struct dns_soa *);
+
+int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *);
+
+size_t dns_soa_print(void *, size_t, struct dns_soa *);
+
+
+/*
+ * PTR R E S O U R C E R E C O R D
+ */
+
+struct dns_ptr {
+ char host[DNS_D_MAXNAME + 1];
+}; /* struct dns_ptr */
+
+int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *);
+
+int dns_ptr_push(struct dns_packet *, struct dns_ptr *);
+
+int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *);
+
+size_t dns_ptr_print(void *, size_t, struct dns_ptr *);
+
+size_t dns_ptr_cname(void *, size_t, struct dns_ptr *);
+
+
+/*
+ * SRV R E S O U R C E R E C O R D
+ */
+
+struct dns_srv {
+ unsigned short priority;
+ unsigned short weight;
+ unsigned short port;
+ char target[DNS_D_MAXNAME + 1];
+}; /* struct dns_srv */
+
+int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *);
+
+int dns_srv_push(struct dns_packet *, struct dns_srv *);
+
+int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *);
+
+size_t dns_srv_print(void *, size_t, struct dns_srv *);
+
+size_t dns_srv_cname(void *, size_t, struct dns_srv *);
+
+
+/*
+ * SSHFP R E S O U R C E R E C O R D
+ */
+
+struct dns_sshfp {
+ enum dns_sshfp_key {
+ DNS_SSHFP_RSA = 1,
+ DNS_SSHFP_DSA = 2,
+ } algo;
+
+ enum dns_sshfp_digest {
+ DNS_SSHFP_SHA1 = 1,
+ } type;
+
+ union {
+ unsigned char sha1[20];
+ } digest;
+}; /* struct dns_sshfp */
+
+int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *);
+
+int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *);
+
+int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *);
+
+size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *);
+
+
+/*
+ * TXT R E S O U R C E R E C O R D
+ */
+
+#ifndef DNS_TXT_MINDATA
+#define DNS_TXT_MINDATA 1024
+#endif
+
+struct dns_txt {
+ size_t size, len;
+ unsigned char data[DNS_TXT_MINDATA];
+}; /* struct dns_txt */
+
+struct dns_txt *dns_txt_init(struct dns_txt *, size_t);
+
+int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *);
+
+int dns_txt_push(struct dns_packet *, struct dns_txt *);
+
+int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *);
+
+size_t dns_txt_print(void *, size_t, struct dns_txt *);
+
+
+/*
+ * ANY R E S O U R C E R E C O R D
+ */
+
+union dns_any {
+ struct dns_a a;
+ struct dns_aaaa aaaa;
+ struct dns_mx mx;
+ struct dns_ns ns;
+ struct dns_cname cname;
+ struct dns_soa soa;
+ struct dns_ptr ptr;
+ struct dns_srv srv;
+ struct dns_sshfp sshfp;
+ struct dns_txt txt, spf, rdata;
+}; /* union dns_any */
+
+#define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) } }
+
+union dns_any *dns_any_init(union dns_any *, size_t);
+
+int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *);
+
+int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type);
+
+int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type);
+
+size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type);
+
+size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type);
+
+
+/*
+ * H O S T S I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_hosts;
+
+struct dns_hosts *dns_hosts_open(int *);
+
+void dns_hosts_close(struct dns_hosts *);
+
+unsigned dns_hosts_acquire(struct dns_hosts *);
+
+unsigned dns_hosts_release(struct dns_hosts *);
+
+struct dns_hosts *dns_hosts_mortal(struct dns_hosts *);
+
+struct dns_hosts *dns_hosts_local(int *);
+
+int dns_hosts_loadfile(struct dns_hosts *, FILE *);
+
+int dns_hosts_loadpath(struct dns_hosts *, const char *);
+
+int dns_hosts_dump(struct dns_hosts *, FILE *);
+
+int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool);
+
+struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *);
+
+
+/*
+ * R E S O L V . C O N F I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_resolv_conf {
+ struct sockaddr_storage nameserver[3];
+
+ char search[4][DNS_D_MAXNAME + 1];
+
+ /* (f)ile, (b)ind, (c)ache */
+ char lookup[3];
+
+ struct {
+ _Bool edns0;
+
+ unsigned ndots;
+
+ unsigned timeout;
+
+ unsigned attempts;
+
+ _Bool rotate;
+
+ _Bool recurse;
+
+ _Bool smart;
+
+ enum {
+ DNS_RESCONF_TCP_ENABLE,
+ DNS_RESCONF_TCP_ONLY,
+ DNS_RESCONF_TCP_DISABLE,
+ } tcp;
+ } options;
+
+ struct sockaddr_storage iface;
+
+ struct { /* PRIVATE */
+ dns_atomic_t refcount;
+ } _;
+}; /* struct dns_resolv_conf */
+
+struct dns_resolv_conf *dns_resconf_open(int *);
+
+void dns_resconf_close(struct dns_resolv_conf *);
+
+unsigned dns_resconf_acquire(struct dns_resolv_conf *);
+
+unsigned dns_resconf_release(struct dns_resolv_conf *);
+
+struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *);
+
+struct dns_resolv_conf *dns_resconf_local(int *);
+
+struct dns_resolv_conf *dns_resconf_root(int *);
+
+int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *);
+
+int dns_resconf_loadpath(struct dns_resolv_conf *, const char *);
+
+int dns_resconf_dump(struct dns_resolv_conf *, FILE *);
+
+int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short);
+
+typedef unsigned long dns_resconf_i_t;
+
+size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *);
+
+
+/*
+ * H I N T S E R V E R I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_hints;
+
+struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *);
+
+void dns_hints_close(struct dns_hints *);
+
+unsigned dns_hints_acquire(struct dns_hints *);
+
+unsigned dns_hints_release(struct dns_hints *);
+
+struct dns_hints *dns_hints_mortal(struct dns_hints *);
+
+int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned);
+
+unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *);
+
+struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *);
+
+struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *);
+
+
+struct dns_hints_i {
+ const char *zone;
+
+ struct {
+ unsigned next;
+ unsigned seed;
+ } state;
+}; /* struct dns_hints_i */
+
+#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ })
+
+unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *);
+
+
+/*
+ * C A C H E I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_cache {
+ void *state;
+
+ dns_atomic_t (*acquire)(struct dns_cache *);
+ dns_atomic_t (*release)(struct dns_cache *);
+
+ struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *);
+
+ int (*submit)(struct dns_packet *, struct dns_cache *);
+ int (*check)(struct dns_cache *);
+ struct dns_packet *(*fetch)(struct dns_cache *, int *);
+
+ int (*pollfd)(struct dns_cache *);
+ short (*events)(struct dns_cache *);
+ void (*clear)(struct dns_cache *);
+
+ union {
+ long i;
+ void *p;
+ } arg[3];
+}; /* struct dns_cache */
+
+
+struct dns_cache *dns_cache_init(struct dns_cache *);
+
+void dns_cache_close(struct dns_cache *);
+
+
+/*
+ * A P P L I C A T I O N I N T E R F A C E
+ *
+ * Options to change the behavior of the API. Applies across all the
+ * different components.
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0
+#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ }
+#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ }
+
+#define dns_opts(...) (&(struct dns_options)DNS_OPTS_INIT(__VA_ARGS__))
+
+struct dns_options {
+ /*
+ * If the callback closes *fd, it must set it to -1. Otherwise, the
+ * descriptor is queued and lazily closed at object destruction or
+ * by an explicit call to _clear(). This allows safe use of
+ * kqueue(2), epoll(2), et al -style persistent events.
+ */
+ struct {
+ void *arg;
+ int (*cb)(int *fd, void *arg);
+ } closefd;
+
+ /* bitmask for _events() routines */
+ enum dns_events {
+ DNS_SYSPOLL,
+ DNS_LIBEVENT,
+ } events;
+}; /* struct dns_options */
+
+
+/*
+ * S T A T S I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_stat {
+ size_t queries;
+
+ struct {
+ struct {
+ size_t count, bytes;
+ } sent, rcvd;
+ } udp, tcp;
+}; /* struct dns_stat */
+
+
+/*
+ * S O C K E T I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_socket;
+
+struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error);
+
+void dns_so_close(struct dns_socket *);
+
+void dns_so_reset(struct dns_socket *);
+
+unsigned short dns_so_mkqid(struct dns_socket *so);
+
+struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *);
+
+int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *);
+
+int dns_so_check(struct dns_socket *);
+
+struct dns_packet *dns_so_fetch(struct dns_socket *, int *);
+
+time_t dns_so_elapsed(struct dns_socket *);
+
+void dns_so_clear(struct dns_socket *);
+
+int dns_so_events(struct dns_socket *);
+
+int dns_so_pollfd(struct dns_socket *);
+
+int dns_so_poll(struct dns_socket *, int);
+
+const struct dns_stat *dns_so_stat(struct dns_socket *);
+
+
+/*
+ * R E S O L V E R I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_resolver;
+
+struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *);
+
+struct dns_resolver *dns_res_stub(const struct dns_options *, int *);
+
+void dns_res_reset(struct dns_resolver *);
+
+void dns_res_close(struct dns_resolver *);
+
+unsigned dns_res_acquire(struct dns_resolver *);
+
+unsigned dns_res_release(struct dns_resolver *);
+
+struct dns_resolver *dns_res_mortal(struct dns_resolver *);
+
+int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class);
+
+int dns_res_check(struct dns_resolver *);
+
+struct dns_packet *dns_res_fetch(struct dns_resolver *, int *);
+
+time_t dns_res_elapsed(struct dns_resolver *);
+
+void dns_res_clear(struct dns_resolver *);
+
+int dns_res_events(struct dns_resolver *);
+
+int dns_res_pollfd(struct dns_resolver *);
+
+int dns_res_poll(struct dns_resolver *, int);
+
+struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *);
+
+const struct dns_stat *dns_res_stat(struct dns_resolver *);
+
+
+/*
+ * A D D R I N F O I N T E R F A C E
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+struct dns_addrinfo;
+
+struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *);
+
+void dns_ai_close(struct dns_addrinfo *);
+
+int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *);
+
+size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *);
+
+time_t dns_ai_elapsed(struct dns_addrinfo *);
+
+void dns_ai_clear(struct dns_addrinfo *);
+
+int dns_ai_events(struct dns_addrinfo *);
+
+int dns_ai_pollfd(struct dns_addrinfo *);
+
+int dns_ai_poll(struct dns_addrinfo *, int);
+
+const struct dns_stat *dns_ai_stat(struct dns_addrinfo *);
+
+void *dns_sa_addr(int af, void *sa);
+unsigned short *dns_sa_port(int af, void *sa);
+#if _WIN32
+const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim);
+#else
+#define dns_inet_pton(...) inet_pton(__VA_ARGS__)
+#define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
+#endif
+#define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
+/*
+ * U T I L I T Y I N T E R F A C E S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+size_t dns_strlcpy(char *, const char *, size_t);
+
+size_t dns_strlcat(char *, const char *, size_t);
+
+
+/*
+ * M A C R O M A G I C S
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b))
+#define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N
+#define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+#define DNS_PP_CALL(F, ...) F(__VA_ARGS__)
+#define DNS_PP_PASTE(x, y) x##y
+#define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y)
+#define DNS_PP_STRINGIFY_(s) #s
+#define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s)
+#define DNS_PP_D1 0
+#define DNS_PP_D2 1
+#define DNS_PP_D3 2
+#define DNS_PP_D4 3
+#define DNS_PP_D5 4
+#define DNS_PP_D6 5
+#define DNS_PP_D7 6
+#define DNS_PP_D8 7
+#define DNS_PP_D9 8
+#define DNS_PP_D10 9
+#define DNS_PP_D11 10
+#define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N)
+
+#endif /* DNS_H */
diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c
new file mode 100644
index 0000000000..056db2eec0
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con.c
@@ -0,0 +1,2596 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+static Eina_Bool _ecore_con_client_timer(Ecore_Con_Client *cl);
+static void _ecore_con_cl_timer_update(Ecore_Con_Client *cl);
+static Eina_Bool _ecore_con_server_timer(Ecore_Con_Server *svr);
+static void _ecore_con_server_timer_update(Ecore_Con_Server *svr);
+
+static void _ecore_con_cb_tcp_connect(void *data,
+ Ecore_Con_Info *info);
+static void _ecore_con_cb_udp_connect(void *data,
+ Ecore_Con_Info *info);
+static void _ecore_con_cb_tcp_listen(void *data,
+ Ecore_Con_Info *info);
+static void _ecore_con_cb_udp_listen(void *data,
+ Ecore_Con_Info *info);
+
+static void _ecore_con_server_free(Ecore_Con_Server *svr);
+static void _ecore_con_client_free(Ecore_Con_Client *cl);
+
+static void _ecore_con_cl_read(Ecore_Con_Server *svr);
+static Eina_Bool _ecore_con_svr_tcp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_cl_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_cl_udp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_svr_udp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+
+static void _ecore_con_svr_cl_read(Ecore_Con_Client *cl);
+static Eina_Bool _ecore_con_svr_cl_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+
+static void _ecore_con_server_flush(Ecore_Con_Server *svr);
+static void _ecore_con_client_flush(Ecore_Con_Client *cl);
+
+static void _ecore_con_event_client_add_free(Ecore_Con_Server *svr,
+ void *ev);
+static void _ecore_con_event_client_del_free(Ecore_Con_Server *svr,
+ void *ev);
+static void _ecore_con_event_client_data_free(Ecore_Con_Server *svr,
+ void *ev);
+static void _ecore_con_event_server_add_free(void *data,
+ void *ev);
+static void _ecore_con_event_server_del_free(void *data,
+ void *ev);
+static void _ecore_con_event_server_data_free(void *data,
+ void *ev);
+static void _ecore_con_event_server_error_free(void *data,
+ Ecore_Con_Event_Server_Error *e);
+static void _ecore_con_event_client_error_free(Ecore_Con_Server *svr,
+ Ecore_Con_Event_Client_Error *e);
+static void _ecore_con_event_server_write_free(void *data,
+ Ecore_Con_Event_Server_Write *e);
+static void _ecore_con_event_client_write_free(Ecore_Con_Server *svr,
+ Ecore_Con_Event_Client_Write *e);
+
+static void _ecore_con_lookup_done(void *data,
+ Ecore_Con_Info *infos);
+
+static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr);
+
+
+void
+_ecore_con_client_kill(Ecore_Con_Client *cl)
+{
+ if (cl->delete_me)
+ DBG("Multi kill request for client %p", cl);
+ else
+ {
+ ecore_con_event_client_del(cl);
+ if (cl->buf) return;
+ }
+ INF("Lost client %s", (cl->ip) ? cl->ip : "");
+ if (cl->fd_handler)
+ ecore_main_fd_handler_del(cl->fd_handler);
+
+ cl->fd_handler = NULL;
+}
+
+void
+_ecore_con_server_kill(Ecore_Con_Server *svr)
+{
+ if (svr->delete_me)
+ DBG("Multi kill request for svr %p", svr);
+ else
+ ecore_con_event_server_del(svr);
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+
+ svr->fd_handler = NULL;
+}
+
+#define _ecore_con_server_kill(svr) do { \
+ DBG("KILL %p", (svr)); \
+ _ecore_con_server_kill((svr)); \
+} while (0)
+
+#define _ecore_con_client_kill(cl) do { \
+ DBG("KILL %p", (cl)); \
+ _ecore_con_client_kill((cl)); \
+} while (0)
+
+EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0;
+EAPI int ECORE_CON_EVENT_SERVER_ADD = 0;
+EAPI int ECORE_CON_EVENT_SERVER_DEL = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_DATA = 0;
+EAPI int ECORE_CON_EVENT_SERVER_DATA = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_WRITE = 0;
+EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0;
+EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0;
+EAPI int ECORE_CON_EVENT_PROXY_BIND = 0;
+
+static Eina_List *servers = NULL;
+static int _ecore_con_init_count = 0;
+static int _ecore_con_event_count = 0;
+int _ecore_con_log_dom = -1;
+Ecore_Con_Socks *_ecore_con_proxy_once = NULL;
+Ecore_Con_Socks *_ecore_con_proxy_global = NULL;
+
+EAPI int
+ecore_con_init(void)
+{
+ if (++_ecore_con_init_count != 1)
+ return _ecore_con_init_count;
+
+#ifdef HAVE_EVIL
+ if (!evil_init())
+ return --_ecore_con_init_count;
+
+#endif
+
+ if (!ecore_init())
+ return --_ecore_con_init_count;
+
+ _ecore_con_log_dom = eina_log_domain_register
+ ("ecore_con", ECORE_CON_DEFAULT_LOG_COLOR);
+ if (_ecore_con_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for Ecore Con.");
+ ecore_shutdown();
+ return --_ecore_con_init_count;
+ }
+
+ ecore_con_mempool_init();
+
+ ECORE_CON_EVENT_CLIENT_ADD = ecore_event_type_new();
+ ECORE_CON_EVENT_CLIENT_DEL = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_ADD = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_DEL = ecore_event_type_new();
+ ECORE_CON_EVENT_CLIENT_DATA = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_DATA = ecore_event_type_new();
+ ECORE_CON_EVENT_CLIENT_WRITE = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_WRITE = ecore_event_type_new();
+ ECORE_CON_EVENT_CLIENT_ERROR = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_ERROR = ecore_event_type_new();
+ ECORE_CON_EVENT_PROXY_BIND = ecore_event_type_new();
+
+
+ eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server");
+ eina_magic_string_set(ECORE_MAGIC_CON_CLIENT, "Ecore_Con_Client");
+ eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url");
+
+ /* TODO Remember return value, if it fails, use gethostbyname() */
+ ecore_con_socks_init();
+ ecore_con_ssl_init();
+ ecore_con_info_init();
+
+ return _ecore_con_init_count;
+}
+
+EAPI int
+ecore_con_shutdown(void)
+{
+ Eina_List *l, *l2;
+ Ecore_Con_Server *svr;
+
+ if (--_ecore_con_init_count != 0)
+ return _ecore_con_init_count;
+
+ EINA_LIST_FOREACH_SAFE(servers, l, l2, svr)
+ {
+ Ecore_Con_Event_Server_Add *ev;
+
+ svr->delete_me = EINA_TRUE;
+ INF("svr %p is dead", svr);
+ /* some pointer hacks here to prevent double frees if people are being stupid */
+ EINA_LIST_FREE(svr->event_count, ev)
+ ev->server = NULL;
+ _ecore_con_server_free(svr);
+ }
+
+ ecore_con_socks_shutdown();
+ if (!_ecore_con_event_count) ecore_con_mempool_shutdown();
+
+ ecore_con_info_shutdown();
+ ecore_con_ssl_shutdown();
+ eina_log_domain_unregister(_ecore_con_log_dom);
+ _ecore_con_log_dom = -1;
+ ecore_shutdown();
+#ifdef HAVE_EVIL
+ evil_shutdown();
+#endif
+
+ return _ecore_con_init_count;
+}
+
+EAPI Eina_Bool
+ecore_con_lookup(const char *name,
+ Ecore_Con_Dns_Cb done_cb,
+ const void *data)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Lookup *lk;
+ struct addrinfo hints;
+
+ if (!name || !done_cb)
+ return EINA_FALSE;
+
+ svr = calloc(1, sizeof(Ecore_Con_Server));
+ if (!svr)
+ return EINA_FALSE;
+
+ lk = malloc(sizeof (Ecore_Con_Lookup));
+ if (!lk)
+ {
+ free(svr);
+ return EINA_FALSE;
+ }
+
+ lk->done_cb = done_cb;
+ lk->data = data;
+
+ svr->name = strdup(name);
+ if (!svr->name)
+ goto on_error;
+
+ svr->type = ECORE_CON_REMOTE_TCP;
+ svr->port = 1025;
+ svr->data = lk;
+ svr->created = EINA_TRUE;
+ svr->reject_excess_clients = EINA_FALSE;
+ svr->client_limit = -1;
+ svr->clients = NULL;
+ svr->ppid = getpid();
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ if (ecore_con_info_get(svr, _ecore_con_lookup_done, svr,
+ &hints))
+ return EINA_TRUE;
+
+ free(svr->name);
+on_error:
+ free(lk);
+ free(svr);
+ return EINA_FALSE;
+}
+
+/**
+ * @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions
+ *
+ * Functions that operate on Ecore server objects.
+ *
+ * @{
+ */
+
+/**
+ * @example ecore_con_server_example.c
+ * Shows how to write a simple server using the Ecore_Con library.
+ */
+
+EAPI Ecore_Con_Server *
+ecore_con_server_add(Ecore_Con_Type compl_type,
+ const char *name,
+ int port,
+ const void *data)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Type type;
+
+ if (port < 0 || !name)
+ return NULL; /* local user socket: FILE: ~/.ecore/[name]/[port] */
+
+ /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */
+ /* remote system socket: TCP/IP: [name]:[port] */
+ svr = calloc(1, sizeof(Ecore_Con_Server));
+ if (!svr)
+ return NULL;
+
+ svr->name = strdup(name);
+ if (!svr->name)
+ goto error;
+
+ svr->type = compl_type;
+ svr->port = port;
+ svr->data = (void *)data;
+ svr->created = EINA_TRUE;
+ svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
+ svr->reject_excess_clients = EINA_FALSE;
+ svr->client_limit = -1;
+ svr->clients = NULL;
+ svr->ppid = getpid();
+ if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL))
+ goto error;
+
+ type = compl_type & ECORE_CON_TYPE;
+
+ if ((type == ECORE_CON_LOCAL_USER) ||
+ (type == ECORE_CON_LOCAL_SYSTEM) ||
+ (type == ECORE_CON_LOCAL_ABSTRACT))
+ /* Local */
+#ifdef _WIN32
+ if (!ecore_con_local_listen(svr))
+ goto error;
+#else
+ if (!ecore_con_local_listen(svr, _ecore_con_svr_tcp_handler, svr))
+ goto error;
+#endif
+
+ if ((type == ECORE_CON_REMOTE_TCP) ||
+ (type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK))
+ {
+ /* TCP */
+ if (!ecore_con_info_tcp_listen(svr, _ecore_con_cb_tcp_listen,
+ svr))
+ goto error;
+ }
+ else if ((type == ECORE_CON_REMOTE_MCAST) ||
+ (type == ECORE_CON_REMOTE_UDP))
+ /* UDP and MCAST */
+ if (!ecore_con_info_udp_listen(svr, _ecore_con_cb_udp_listen,
+ svr))
+ goto error;
+
+ servers = eina_list_append(servers, svr);
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
+
+ return svr;
+
+error:
+ if (svr->name)
+ free(svr->name);
+
+ if (svr->path)
+ free(svr->path);
+
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+
+ if (svr->fd > 0)
+ close(svr->fd);
+
+ if (svr->buf)
+ eina_binbuf_free(svr->buf);
+
+ if (svr->ip)
+ eina_stringshare_del(svr->ip);
+
+ ecore_con_ssl_server_shutdown(svr);
+ free(svr);
+ return NULL;
+}
+
+EAPI Ecore_Con_Server *
+ecore_con_server_connect(Ecore_Con_Type compl_type,
+ const char *name,
+ int port,
+ const void *data)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Type type;
+
+ if ((!name) || (!name[0]))
+ return NULL;
+ /* local user socket: FILE: ~/.ecore/[name]/[port] */
+ /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */
+ /* remote system socket: TCP/IP: [name]:[port] */
+ svr = calloc(1, sizeof(Ecore_Con_Server));
+ if (!svr)
+ return NULL;
+
+ svr->name = strdup(name);
+ if (!svr->name)
+ goto error;
+
+ svr->type = compl_type;
+ svr->port = port;
+ svr->data = (void *)data;
+ svr->created = EINA_FALSE;
+ svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
+ svr->disable_proxy = (compl_type & ECORE_CON_SUPER_SSL & ECORE_CON_NO_PROXY) == ECORE_CON_NO_PROXY;
+ svr->reject_excess_clients = EINA_FALSE;
+ svr->clients = NULL;
+ svr->client_limit = -1;
+
+ type = compl_type & ECORE_CON_TYPE;
+
+ if ((!svr->disable_proxy) && (type > ECORE_CON_LOCAL_ABSTRACT))
+ {
+ /* never use proxies on local connections */
+ if (_ecore_con_proxy_once)
+ svr->ecs = _ecore_con_proxy_once;
+ else if (_ecore_con_proxy_global)
+ svr->ecs = _ecore_con_proxy_global;
+ _ecore_con_proxy_once = NULL;
+ if (svr->ecs)
+ {
+ if ((!svr->ecs->lookup) &&
+ (!ecore_con_lookup(svr->name, (Ecore_Con_Dns_Cb)ecore_con_socks_dns_cb, svr)))
+ goto error;
+ if (svr->ecs->lookup)
+ svr->ecs_state = ECORE_CON_PROXY_STATE_RESOLVED;
+ }
+ }
+ EINA_SAFETY_ON_TRUE_GOTO(ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL), error);
+
+ EINA_SAFETY_ON_TRUE_GOTO(((type == ECORE_CON_REMOTE_TCP) ||
+ (type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK) ||
+ (type == ECORE_CON_REMOTE_UDP) ||
+ (type == ECORE_CON_REMOTE_BROADCAST)) &&
+ (port < 0), error);
+
+ if ((type == ECORE_CON_LOCAL_USER) ||
+ (type == ECORE_CON_LOCAL_SYSTEM) ||
+ (type == ECORE_CON_LOCAL_ABSTRACT))
+ /* Local */
+#ifdef _WIN32
+ EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler), error);
+#else
+ EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler, svr), error);
+#endif
+
+ if ((type == ECORE_CON_REMOTE_TCP) ||
+ (type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK))
+ {
+ /* TCP */
+ EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect, svr), error);
+ }
+ else if ((type == ECORE_CON_REMOTE_UDP) || (type == ECORE_CON_REMOTE_BROADCAST))
+ /* UDP and MCAST */
+ EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_udp_connect(svr, _ecore_con_cb_udp_connect, svr), error);
+
+ servers = eina_list_append(servers, svr);
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
+
+ return svr;
+
+error:
+ if (svr->name)
+ free(svr->name);
+
+ if (svr->path)
+ free(svr->path);
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+
+ if (svr->fd > 0)
+ close(svr->fd);
+
+ ecore_con_ssl_server_shutdown(svr);
+ free(svr);
+ return NULL;
+}
+
+EAPI void
+ecore_con_server_timeout_set(Ecore_Con_Server *svr,
+ double timeout)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_set");
+ return;
+ }
+
+ if (svr->created)
+ svr->client_disconnect_time = timeout;
+ else
+ svr->disconnect_time = timeout;
+}
+
+EAPI double
+ecore_con_server_timeout_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_get");
+ return 0;
+ }
+
+ return svr->created ? svr->client_disconnect_time : svr->disconnect_time;
+}
+
+EAPI void *
+ecore_con_server_del(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del");
+ return NULL;
+ }
+
+ if (svr->delete_me)
+ return NULL;
+
+ _ecore_con_server_kill(svr);
+ return svr->data;
+}
+
+EAPI void *
+ecore_con_server_data_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
+ return NULL;
+ }
+
+ return svr->data;
+}
+
+EAPI void *
+ecore_con_server_data_set(Ecore_Con_Server *svr,
+ void *data)
+{
+ void *ret = NULL;
+
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
+ return NULL;
+ }
+
+ ret = svr->data;
+ svr->data = data;
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_con_server_connected_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get");
+ return EINA_FALSE;
+ }
+
+ if (svr->connecting)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+EAPI const Eina_List *
+ecore_con_server_clients_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+ "ecore_con_server_clients_get");
+ return NULL;
+ }
+
+ return svr->clients;
+}
+
+EAPI const char *
+ecore_con_server_name_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+ "ecore_con_server_name_get");
+ return NULL;
+ }
+
+ return svr->name;
+}
+
+EAPI int
+ecore_con_server_port_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+ "ecore_con_server_port_get");
+ return -1;
+ }
+ return svr->port;
+}
+
+EAPI int
+ecore_con_server_send(Ecore_Con_Server *svr,
+ const void *data,
+ int size)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send");
+ return 0;
+ }
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, 0);
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
+
+ if (!svr->buf)
+ {
+ svr->buf = eina_binbuf_new();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(svr->buf, 0);
+#ifdef TCP_CORK
+ if ((svr->fd >= 0) && ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
+ {
+ int state = 1;
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("corking failed! %s", strerror(errno));
+ }
+#endif
+ }
+ eina_binbuf_append_length(svr->buf, data, size);
+
+ return size;
+}
+
+EAPI void
+ecore_con_server_client_limit_set(Ecore_Con_Server *svr,
+ int client_limit,
+ char reject_excess_clients)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+ "ecore_con_server_client_limit_set");
+ return;
+ }
+
+ svr->client_limit = client_limit;
+ svr->reject_excess_clients = reject_excess_clients;
+}
+
+EAPI const char *
+ecore_con_server_ip_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get");
+ return NULL;
+ }
+
+ return svr->ip;
+}
+
+EAPI double
+ecore_con_server_uptime_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_uptime_get");
+ return -1;
+ }
+
+ return ecore_time_get() - svr->start_time;
+}
+
+EAPI void
+ecore_con_server_flush(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush");
+ return;
+ }
+
+ _ecore_con_server_flush(svr);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions
+ *
+ * Functions that operate on Ecore connection client objects.
+ *
+ * @{
+ */
+
+/**
+ * @example ecore_con_client_example.c
+ * Shows how to write a simple client that connects to the example server.
+ */
+
+EAPI int
+ecore_con_client_send(Ecore_Con_Client *cl,
+ const void *data,
+ int size)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send");
+ return 0;
+ }
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, 0);
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
+
+ if (cl->fd_handler)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
+
+ if (cl->host_server && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP))
+ sendto(cl->host_server->fd, data, size, 0, (struct sockaddr *)cl->client_addr,
+ cl->client_addr_len);
+ else if (!cl->buf)
+ {
+ cl->buf = eina_binbuf_new();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cl->buf, 0);
+#ifdef TCP_CORK
+ if ((cl->fd >= 0) && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
+ {
+ int state = 1;
+ if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("corking failed! %s", strerror(errno));
+ }
+#endif
+ }
+ eina_binbuf_append_length(cl->buf, data, size);
+
+ return size;
+}
+
+EAPI Ecore_Con_Server *
+ecore_con_client_server_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+ "ecore_con_client_server_get");
+ return NULL;
+ }
+
+ return cl->host_server;
+}
+
+EAPI Eina_Bool
+ecore_con_client_connected_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+ "ecore_con_client_connected_get");
+ return EINA_FALSE;
+ }
+
+ return !cl->delete_me;
+}
+
+EAPI void
+ecore_con_client_timeout_set(Ecore_Con_Client *cl,
+ double timeout)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+ "ecore_con_client_timeout_set");
+ return;
+ }
+
+ cl->disconnect_time = timeout;
+
+ _ecore_con_cl_timer_update(cl);
+}
+
+EAPI double
+ecore_con_client_timeout_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_timeout_get");
+ return 0;
+ }
+
+ return cl->disconnect_time;
+}
+
+EAPI void *
+ecore_con_client_del(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del");
+ return NULL;
+ }
+
+ _ecore_con_client_kill(cl);
+ return cl->data;
+}
+
+EAPI void
+ecore_con_client_data_set(Ecore_Con_Client *cl,
+ const void *data)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set");
+ return;
+ }
+
+ cl->data = (void *)data;
+}
+
+EAPI void *
+ecore_con_client_data_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get");
+ return NULL;
+ }
+
+ return cl->data;
+}
+
+EAPI const char *
+ecore_con_client_ip_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_ip_get");
+ return NULL;
+ }
+ if (!cl->ip)
+ cl->ip = _ecore_con_pretty_ip(cl->client_addr);
+
+ return cl->ip;
+}
+
+EAPI int
+ecore_con_client_port_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_port_get");
+ return -1;
+ }
+ if (cl->client_addr->sa_family == AF_INET)
+ return ((struct sockaddr_in*)cl->client_addr)->sin_port;
+#ifdef HAVE_IPV6
+ return ((struct sockaddr_in6*)cl->client_addr)->sin6_port;
+#else
+ return -1;
+#endif
+}
+
+EAPI double
+ecore_con_client_uptime_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_uptime_get");
+ return -1;
+ }
+
+ return ecore_time_get() - cl->start_time;
+}
+
+EAPI void
+ecore_con_client_flush(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_flush");
+ return;
+ }
+
+ _ecore_con_client_flush(cl);
+}
+
+EAPI int
+ecore_con_server_fd_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return -1;
+ }
+ if (svr->created) return -1;
+ if (svr->delete_me) return -1;
+ return ecore_main_fd_handler_fd_get(svr->fd_handler);
+}
+
+EAPI int
+ecore_con_client_fd_get(Ecore_Con_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__);
+ return -1;
+ }
+ return ecore_main_fd_handler_fd_get(cl->fd_handler);
+}
+
+/**
+ * @}
+ */
+
+void
+ecore_con_event_proxy_bind(Ecore_Con_Server *svr)
+{
+ Ecore_Con_Event_Proxy_Bind *e;
+ int ev = ECORE_CON_EVENT_PROXY_BIND;
+
+ e = ecore_con_event_proxy_bind_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ svr->event_count = eina_list_append(svr->event_count, e);
+ _ecore_con_server_timer_update(svr);
+ e->server = svr;
+ e->ip = svr->proxyip;
+ e->port = svr->proxyport;
+ ecore_event_add(ev, e,
+ _ecore_con_event_server_add_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_server_add(Ecore_Con_Server *svr)
+{
+ /* we got our server! */
+ Ecore_Con_Event_Server_Add *e;
+ int ev = ECORE_CON_EVENT_SERVER_ADD;
+
+ e = ecore_con_event_server_add_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ svr->connecting = EINA_FALSE;
+ svr->start_time = ecore_time_get();
+ svr->event_count = eina_list_append(svr->event_count, e);
+ _ecore_con_server_timer_update(svr);
+ e->server = svr;
+ if (svr->upgrade) ev = ECORE_CON_EVENT_SERVER_UPGRADE;
+ ecore_event_add(ev, e,
+ _ecore_con_event_server_add_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_server_del(Ecore_Con_Server *svr)
+{
+ Ecore_Con_Event_Server_Del *e;
+
+ svr->delete_me = EINA_TRUE;
+ INF("svr %p is dead", svr);
+ e = ecore_con_event_server_del_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ svr->event_count = eina_list_append(svr->event_count, e);
+ _ecore_con_server_timer_update(svr);
+ e->server = svr;
+ if (svr->ecs)
+ {
+ svr->ecs_state = svr->ecs->lookup ? ECORE_CON_PROXY_STATE_RESOLVED : ECORE_CON_PROXY_STATE_DONE;
+ eina_stringshare_replace(&svr->proxyip, NULL);
+ svr->proxyport = 0;
+ }
+ ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e,
+ _ecore_con_event_server_del_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_server_write(Ecore_Con_Server *svr, int num)
+{
+ Ecore_Con_Event_Server_Write *e;
+
+ e = ecore_con_event_server_write_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ INF("Wrote %d bytes", num);
+ svr->event_count = eina_list_append(svr->event_count, e);
+ e->server = svr;
+ e->size = num;
+ ecore_event_add(ECORE_CON_EVENT_SERVER_WRITE, e,
+ (Ecore_End_Cb)_ecore_con_event_server_write_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate)
+{
+ Ecore_Con_Event_Server_Data *e;
+
+ e = ecore_con_event_server_data_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ svr->event_count = eina_list_append(svr->event_count, e);
+ _ecore_con_server_timer_update(svr);
+ e->server = svr;
+ if (duplicate)
+ {
+ e->data = malloc(num);
+ if (!e->data)
+ {
+ ERR("server data allocation failure !");
+ _ecore_con_event_server_data_free(NULL, e);
+ return;
+ }
+ memcpy(e->data, buf, num);
+ }
+ else
+ e->data = buf;
+ e->size = num;
+ ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, e,
+ _ecore_con_event_server_data_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_add(Ecore_Con_Client *cl)
+{
+ Ecore_Con_Event_Client_Add *e;
+ int ev = ECORE_CON_EVENT_CLIENT_ADD;
+
+ e = ecore_con_event_client_add_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ cl->event_count = eina_list_append(cl->event_count, e);
+ cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+ _ecore_con_cl_timer_update(cl);
+ e->client = cl;
+ if (cl->upgrade) ev = ECORE_CON_EVENT_CLIENT_UPGRADE;
+ ecore_event_add(ev, e,
+ (Ecore_End_Cb)_ecore_con_event_client_add_free, cl->host_server);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_del(Ecore_Con_Client *cl)
+{
+ Ecore_Con_Event_Client_Del *e;
+
+ if (!cl) return;
+ cl->delete_me = EINA_TRUE;
+ INF("cl %p is dead", cl);
+ e = ecore_con_event_client_del_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+ cl->event_count = eina_list_append(cl->event_count, e);
+
+ cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+ _ecore_con_cl_timer_update(cl);
+ e->client = cl;
+ ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e,
+ (Ecore_End_Cb)_ecore_con_event_client_del_free, cl->host_server);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_write(Ecore_Con_Client *cl, int num)
+{
+ Ecore_Con_Event_Client_Write *e;
+
+ e = ecore_con_event_client_write_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ cl->event_count = eina_list_append(cl->event_count, e);
+ cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+ e->client = cl;
+ e->size = num;
+ ecore_event_add(ECORE_CON_EVENT_CLIENT_WRITE, e,
+ (Ecore_End_Cb)_ecore_con_event_client_write_free, cl->host_server);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate)
+{
+ Ecore_Con_Event_Client_Data *e;
+
+ e = ecore_con_event_client_data_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ cl->event_count = eina_list_append(cl->event_count, e);
+ cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+ _ecore_con_cl_timer_update(cl);
+ e->client = cl;
+ if (duplicate)
+ {
+ e->data = malloc(num);
+ if (!e->data)
+ {
+ ERR("client data allocation failure !");
+ _ecore_con_event_client_data_free(cl->host_server, e);
+ return;
+ }
+ memcpy(e->data, buf, num);
+ }
+ else
+ e->data = buf;
+ e->size = num;
+ ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, e,
+ (Ecore_End_Cb)_ecore_con_event_client_data_free, cl->host_server);
+ _ecore_con_event_count++;
+}
+
+
+void
+ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info)
+{
+ svr->infos = eina_list_remove(svr->infos, info);
+}
+
+void
+_ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate)
+{
+ Ecore_Con_Event_Server_Error *e;
+
+ e = ecore_con_event_server_error_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ e->server = svr;
+ e->error = duplicate ? strdup(error) : error;
+ ERR("%s", error);
+ svr->event_count = eina_list_append(svr->event_count, e);
+ ecore_event_add(ECORE_CON_EVENT_SERVER_ERROR, e, (Ecore_End_Cb)_ecore_con_event_server_error_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error)
+{
+ Ecore_Con_Event_Client_Error *e;
+
+ e = ecore_con_event_client_error_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ e->client = cl;
+ e->error = strdup(error);
+ ERR("%s", error);
+ cl->event_count = eina_list_append(cl->event_count, e);
+ cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+ ecore_event_add(ECORE_CON_EVENT_CLIENT_ERROR, e, (Ecore_End_Cb)_ecore_con_event_client_error_free, cl->host_server);
+ _ecore_con_event_count++;
+}
+
+static void
+_ecore_con_server_free(Ecore_Con_Server *svr)
+{
+ Ecore_Con_Client *cl;
+ double t_start, t;
+
+ if (svr->event_count) return;
+
+ while (svr->infos)
+ {
+ ecore_con_info_data_clear(svr->infos->data);
+ svr->infos = eina_list_remove_list(svr->infos, svr->infos);
+ }
+
+ t_start = ecore_time_get();
+ while (svr->buf && (!svr->delete_me))
+ {
+ _ecore_con_server_flush(svr);
+ t = ecore_time_get();
+ if ((t - t_start) > 0.5)
+ {
+ WRN("ECORE_CON: EEK - stuck in _ecore_con_server_free() trying\n"
+ " to flush data out from the server, and have been for\n"
+ " %1.1f seconds. This is taking too long. Aborting flush.",
+ (t - t_start));
+ break;
+ }
+ }
+
+#ifdef _WIN32
+ ecore_con_local_win32_server_del(svr);
+#endif
+ if (svr->event_count) return;
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE);
+
+ if (svr->buf)
+ eina_binbuf_free(svr->buf);
+
+ EINA_LIST_FREE(svr->clients, cl)
+ {
+ Ecore_Con_Event_Server_Add *ev;
+
+ /* some pointer hacks here to prevent double frees if people are being stupid */
+ EINA_LIST_FREE(cl->event_count, ev)
+ ev->server = NULL;
+ cl->delete_me = EINA_TRUE;
+ INF("cl %p is dead", cl);
+ _ecore_con_client_free(cl);
+ }
+ if ((svr->created) && (svr->path) && (svr->ppid == getpid()))
+ unlink(svr->path);
+
+ ecore_con_ssl_server_shutdown(svr);
+ free(svr->name);
+
+ free(svr->path);
+
+ eina_stringshare_del(svr->ip);
+ eina_stringshare_del(svr->verify_name);
+
+ if (svr->ecs_buf) eina_binbuf_free(svr->ecs_buf);
+ if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+
+ if (svr->fd > 0)
+ close(svr->fd);
+
+ if (svr->until_deletion)
+ ecore_timer_del(svr->until_deletion);
+
+ servers = eina_list_remove(servers, svr);
+ svr->data = NULL;
+ free(svr);
+}
+
+static void
+_ecore_con_client_free(Ecore_Con_Client *cl)
+{
+ double t_start, t;
+
+ if (cl->event_count) return;
+
+ t_start = ecore_time_get();
+ while ((cl->buf) && (!cl->delete_me))
+ {
+ _ecore_con_client_flush(cl);
+ t = ecore_time_get();
+ if ((t - t_start) > 0.5)
+ {
+ WRN("EEK - stuck in _ecore_con_client_free() trying\n"
+ " to flush data out from the client, and have been for\n"
+ " %1.1f seconds. This is taking too long. Aborting flush.",
+ (t - t_start));
+ break;
+ }
+ }
+ cl->host_server->clients = eina_list_remove(cl->host_server->clients, cl);
+
+#ifdef _WIN32
+ ecore_con_local_win32_client_del(cl);
+#endif
+
+ if (cl->event_count) return;
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE);
+
+ if (cl->buf) eina_binbuf_free(cl->buf);
+
+ if (cl->host_server->type & ECORE_CON_SSL)
+ ecore_con_ssl_client_shutdown(cl);
+
+ if (cl->fd_handler)
+ ecore_main_fd_handler_del(cl->fd_handler);
+
+ if (cl->fd > 0)
+ close(cl->fd);
+
+ free(cl->client_addr);
+ cl->client_addr = NULL;
+
+ if (cl->until_deletion)
+ ecore_timer_del(cl->until_deletion);
+
+ eina_stringshare_del(cl->ip);
+ cl->data = NULL;
+ free(cl);
+ return;
+}
+
+static Eina_Bool
+_ecore_con_server_timer(Ecore_Con_Server *svr)
+{
+ ecore_con_server_del(svr);
+
+ svr->until_deletion = NULL;
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_con_server_timer_update(Ecore_Con_Server *svr)
+{
+ if (svr->disconnect_time)
+ {
+ if (svr->disconnect_time > 0)
+ {
+ if (svr->until_deletion)
+ ecore_timer_interval_set(svr->until_deletion, svr->disconnect_time);
+ else
+ svr->until_deletion = ecore_timer_add(svr->disconnect_time, (Ecore_Task_Cb)_ecore_con_server_timer, svr);
+ }
+ else if (svr->until_deletion)
+ {
+ ecore_timer_del(svr->until_deletion);
+ svr->until_deletion = NULL;
+ }
+ }
+ else
+ {
+ if (svr->until_deletion)
+ {
+ ecore_timer_del(svr->until_deletion);
+ svr->until_deletion = NULL;
+ }
+ }
+}
+
+static Eina_Bool
+_ecore_con_client_timer(Ecore_Con_Client *cl)
+{
+ ecore_con_client_del(cl);
+
+ cl->until_deletion = NULL;
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_con_cl_timer_update(Ecore_Con_Client *cl)
+{
+ if (cl->disconnect_time)
+ {
+ if (cl->disconnect_time > 0)
+ {
+ if (cl->until_deletion)
+ ecore_timer_interval_set(cl->until_deletion, cl->disconnect_time);
+ else
+ cl->until_deletion = ecore_timer_add(cl->disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl);
+ }
+ else if (cl->until_deletion)
+ {
+ ecore_timer_del(cl->until_deletion);
+ cl->until_deletion = NULL;
+ }
+ }
+ else
+ {
+ if (cl->host_server->client_disconnect_time > 0)
+ {
+ if (cl->until_deletion)
+ ecore_timer_interval_set(cl->until_deletion, cl->host_server->client_disconnect_time);
+ else
+ cl->until_deletion = ecore_timer_add(cl->host_server->client_disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl);
+ }
+ else if (cl->until_deletion)
+ {
+ ecore_timer_del(cl->until_deletion);
+ cl->until_deletion = NULL;
+ }
+ }
+}
+
+static void
+_ecore_con_cb_tcp_listen(void *data,
+ Ecore_Con_Info *net_info)
+{
+ Ecore_Con_Server *svr;
+ struct linger lin;
+ const char *memerr = NULL;
+
+ svr = data;
+
+ errno = 0;
+ if (!net_info) /* error message has already been handled */
+ {
+ svr->delete_me = EINA_TRUE;
+ goto error;
+ }
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
+ net_info->info.ai_protocol);
+ if (svr->fd < 0) goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+
+ lin.l_onoff = 1;
+ lin.l_linger = 0;
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
+ sizeof(struct linger)) < 0)
+ goto error;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
+ {
+#ifdef HAVE_NETINET_TCP_H
+ int flag = 1;
+
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
+ sizeof(int)) < 0)
+#endif
+ {
+ goto error;
+ }
+ }
+
+ if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+
+ if (listen(svr->fd, 4096) < 0) goto error;
+
+ svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ _ecore_con_svr_tcp_handler, svr, NULL, NULL);
+ if (!svr->fd_handler)
+ {
+ memerr = "Memory allocation failure";
+ goto error;
+ }
+
+ return;
+
+error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+}
+
+static void
+_ecore_con_cb_udp_listen(void *data,
+ Ecore_Con_Info *net_info)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Type type;
+ struct ip_mreq mreq;
+#ifdef HAVE_IPV6
+ struct ipv6_mreq mreq6;
+#endif
+ const int on = 1;
+ const char *memerr = NULL;
+
+ svr = data;
+ type = svr->type;
+ type &= ECORE_CON_TYPE;
+
+ errno = 0;
+ if (!net_info) /* error message has already been handled */
+ {
+ svr->delete_me = EINA_TRUE;
+ goto error;
+ }
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
+ net_info->info.ai_protocol);
+ if (svr->fd < 0) goto error;
+
+ if (type == ECORE_CON_REMOTE_MCAST)
+ {
+ if (net_info->info.ai_family == AF_INET)
+ {
+ if (!inet_pton(net_info->info.ai_family, net_info->ip,
+ &mreq.imr_multiaddr))
+ goto error;
+
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (const void *)&mreq, sizeof(mreq)) != 0)
+ goto error;
+ }
+#ifdef HAVE_IPV6
+ else if (net_info->info.ai_family == AF_INET6)
+ {
+ if (!inet_pton(net_info->info.ai_family, net_info->ip,
+ &mreq6.ipv6mr_multiaddr))
+ goto error;
+ mreq6.ipv6mr_interface = htonl(INADDR_ANY);
+ if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (const void *)&mreq6, sizeof(mreq6)) != 0)
+ goto error;
+ }
+#endif
+ }
+
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0)
+ goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+
+ if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ _ecore_con_svr_udp_handler, svr, NULL, NULL);
+ if (!svr->fd_handler)
+ {
+ memerr = "Memory allocation failure";
+ goto error;
+ }
+
+ svr->ip = eina_stringshare_add(net_info->ip);
+
+ return;
+
+error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+}
+
+static void
+_ecore_con_cb_tcp_connect(void *data,
+ Ecore_Con_Info *net_info)
+{
+ Ecore_Con_Server *svr;
+ int res;
+ int curstate = 0;
+ const char *memerr = NULL;
+
+ svr = data;
+
+ errno = 0;
+ if (!net_info) /* error message has already been handled */
+ {
+ svr->delete_me = EINA_TRUE;
+ goto error;
+ }
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
+ net_info->info.ai_protocol);
+ if (svr->fd < 0) goto error;
+
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0)
+ goto error;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
+ {
+#ifdef HAVE_NETINET_TCP_H
+ int flag = 1;
+
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0)
+#endif
+ {
+ goto error;
+ }
+ }
+
+ res = connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen);
+#ifdef _WIN32
+ if (res == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() != WSAEINPROGRESS)
+ {
+ char *err;
+ err = evil_format_message(WSAGetLastError());
+ _ecore_con_event_server_error(svr, err, EINA_FALSE);
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+ return;
+ }
+
+#else
+ if (res < 0)
+ {
+ if (errno != EINPROGRESS) goto error;
+#endif
+ svr->connecting = EINA_TRUE;
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
+ _ecore_con_cl_handler, svr, NULL, NULL);
+ }
+ else
+ svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ _ecore_con_cl_handler, svr, NULL, NULL);
+
+ if (svr->type & ECORE_CON_SSL)
+ {
+ svr->handshaking = EINA_TRUE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_INIT;
+ DBG("%s ssl handshake", svr->ecs_state ? "Queuing" : "Beginning");
+ if ((!svr->ecs_state) && ecore_con_ssl_server_init(svr))
+ goto error;
+ }
+
+ if (!svr->fd_handler)
+ {
+ memerr = "Memory allocation failure";
+ goto error;
+ }
+
+ if ((!svr->ecs) || (svr->ecs->lookup))
+ svr->ip = eina_stringshare_add(net_info->ip);
+
+ return;
+
+error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+}
+
+static void
+_ecore_con_cb_udp_connect(void *data,
+ Ecore_Con_Info *net_info)
+{
+ Ecore_Con_Server *svr;
+ int curstate = 0;
+ int broadcast = 1;
+ const char *memerr = NULL;
+ svr = data;
+
+ errno = 0;
+ if (!net_info) /* error message has already been handled */
+ {
+ svr->delete_me = EINA_TRUE;
+ goto error;
+ }
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
+ net_info->info.ai_protocol);
+ if (svr->fd < 0) goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_BROADCAST)
+ {
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_BROADCAST,
+ (const void *)&broadcast,
+ sizeof(broadcast)) < 0)
+ {
+ goto error;
+ }
+ }
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&curstate, sizeof(curstate)) < 0)
+ goto error;
+
+ if (connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+
+ svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
+ _ecore_con_cl_udp_handler, svr, NULL, NULL);
+
+ if (!svr->fd_handler)
+ {
+ memerr = "Memory allocation failure";
+ goto error;
+ }
+
+ if ((!svr->ecs) || (svr->ecs->lookup))
+ svr->ip = eina_stringshare_add(net_info->ip);
+
+ return;
+
+error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+}
+
+static Ecore_Con_State
+svr_try_connect_plain(Ecore_Con_Server *svr)
+{
+ int res;
+ int so_err = 0;
+ socklen_t size = sizeof(int);
+
+ res = getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &size);
+#ifdef _WIN32
+ if (res == SOCKET_ERROR)
+ so_err = WSAGetLastError();
+
+ if ((so_err == WSAEINPROGRESS) && !svr->delete_me)
+ return ECORE_CON_INPROGRESS;
+
+#else
+ if (res < 0)
+ so_err = errno;
+
+ if ((so_err == EINPROGRESS) && !svr->delete_me)
+ return ECORE_CON_INPROGRESS;
+
+#endif
+
+ if (so_err)
+ {
+ /* we lost our server! */
+ ecore_con_event_server_error(svr, strerror(so_err));
+ ERR("Connection lost: %s", strerror(so_err));
+ _ecore_con_server_kill(svr);
+ return ECORE_CON_DISCONNECTED;
+ }
+
+ if ((!svr->delete_me) && (!svr->handshaking) && svr->connecting)
+ {
+ if (svr->ecs)
+ {
+ if (ecore_con_socks_svr_init(svr))
+ return ECORE_CON_INPROGRESS;
+ }
+ else
+ ecore_con_event_server_add(svr);
+ }
+
+ if (svr->fd_handler && (!svr->buf))
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+
+ if (!svr->delete_me)
+ return ECORE_CON_CONNECTED;
+ else
+ return ECORE_CON_DISCONNECTED;
+}
+
+static const char *
+_ecore_con_pretty_ip(struct sockaddr *client_addr)
+{
+#ifndef HAVE_IPV6
+ char ipbuf[INET_ADDRSTRLEN + 1];
+#else
+ char ipbuf[INET6_ADDRSTRLEN + 1];
+#endif
+ int family = client_addr->sa_family;
+ void *src;
+
+ switch(family)
+ {
+ case AF_INET:
+ src = &(((struct sockaddr_in *)client_addr)->sin_addr);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ src = &(((struct sockaddr_in6 *)client_addr)->sin6_addr);
+
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src))
+ {
+ family = AF_INET;
+ src = (char*)src + 12;
+ }
+ break;
+#endif
+ default:
+ return eina_stringshare_add("0.0.0.0");
+ }
+
+ if (!inet_ntop(family, src, ipbuf, sizeof(ipbuf)))
+ return eina_stringshare_add("0.0.0.0");
+
+ ipbuf[sizeof(ipbuf) - 1] = 0;
+ return eina_stringshare_add(ipbuf);
+}
+
+static Eina_Bool
+_ecore_con_svr_tcp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Client *cl = NULL;
+ unsigned char client_addr[256];
+ unsigned int client_addr_len;
+ const char *clerr = NULL;
+
+ svr = data;
+ if (svr->delete_me)
+ return ECORE_CALLBACK_RENEW;
+
+ if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) &&
+ (svr->client_count >= (unsigned int)svr->client_limit))
+ return ECORE_CALLBACK_RENEW;
+
+ /* a new client */
+
+ cl = calloc(1, sizeof(Ecore_Con_Client));
+ if (!cl)
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure when attempting to add a new client");
+ return ECORE_CALLBACK_RENEW;
+ }
+ cl->host_server = svr;
+
+ client_addr_len = sizeof(client_addr);
+ memset(&client_addr, 0, client_addr_len);
+ cl->fd = accept(svr->fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len);
+ if (cl->fd < 0) goto error;
+ if ((svr->client_limit >= 0) && (svr->reject_excess_clients) &&
+ (svr->client_count >= (unsigned int)svr->client_limit))
+ {
+ clerr = "Maximum client limit reached";
+ goto error;
+ }
+
+ if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+ cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ,
+ _ecore_con_svr_cl_handler, cl, NULL, NULL);
+ if (!cl->fd_handler) goto error;
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+
+ if ((!svr->upgrade) && (svr->type & ECORE_CON_SSL))
+ {
+ cl->handshaking = EINA_TRUE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_INIT;
+ if (ecore_con_ssl_client_init(cl))
+ goto error;
+ }
+
+ cl->client_addr = malloc(client_addr_len);
+ if (!cl->client_addr)
+ {
+ clerr = "Memory allocation failure when attempting to add a new client";
+ goto error;
+ }
+ cl->client_addr_len = client_addr_len;
+ memcpy(cl->client_addr, &client_addr, client_addr_len);
+
+ svr->clients = eina_list_append(svr->clients, cl);
+ svr->client_count++;
+
+ if ((!cl->delete_me) && (!cl->handshaking))
+ ecore_con_event_client_add(cl);
+
+ return ECORE_CALLBACK_RENEW;
+
+error:
+ if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler);
+ if (cl->fd >= 0) close(cl->fd);
+ {
+ Ecore_Event *ev;
+
+ EINA_LIST_FREE(cl->event_count, ev)
+ {
+ svr->event_count = eina_list_remove(svr->event_count, ev);
+ ecore_event_del(ev);
+ }
+ }
+ free(cl);
+ if (clerr || errno) ecore_con_event_server_error(svr, clerr ?: strerror(errno));
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_con_cl_read(Ecore_Con_Server *svr)
+{
+ int num = 0;
+ Eina_Bool lost_server = EINA_TRUE;
+ unsigned char buf[READBUFSIZ];
+
+ DBG("svr=%p", svr);
+
+ /* only possible with non-ssl connections */
+ if (svr->connecting && (svr_try_connect_plain(svr) != ECORE_CON_CONNECTED))
+ return;
+
+ if (svr->handshaking && (!svr->ecs_state))
+ {
+ DBG("Continuing ssl handshake");
+ if (!ecore_con_ssl_server_init(svr))
+ lost_server = EINA_FALSE;
+ _ecore_con_server_timer_update(svr);
+ }
+
+ if (svr->ecs_state || !(svr->type & ECORE_CON_SSL))
+ {
+ errno = 0;
+ num = read(svr->fd, buf, sizeof(buf));
+ /* 0 is not a valid return value for a tcp socket */
+ if ((num > 0) || ((num < 0) && (errno == EAGAIN)))
+ lost_server = EINA_FALSE;
+ else if (num < 0)
+ ecore_con_event_server_error(svr, strerror(errno));
+ }
+ else
+ {
+ num = ecore_con_ssl_server_read(svr, buf, sizeof(buf));
+ /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */
+ if (num >= 0)
+ lost_server = EINA_FALSE;
+ }
+
+ if ((!svr->delete_me) && (num > 0))
+ {
+ if (svr->ecs_state)
+ ecore_con_socks_read(svr, buf, num);
+ else
+ ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+ }
+
+ if (lost_server)
+ _ecore_con_server_kill(svr);
+}
+
+static Eina_Bool
+_ecore_con_cl_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ Ecore_Con_Server *svr;
+ Eina_Bool want_read, want_write;
+
+ svr = data;
+ if (svr->delete_me)
+ return ECORE_CALLBACK_RENEW;
+
+ if (svr->delete_me)
+ return ECORE_CALLBACK_RENEW;
+
+ want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ);
+ want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE);
+
+ if ((!svr->ecs_state) && svr->handshaking && (want_read || want_write))
+ {
+ DBG("Continuing ssl handshake: preparing to %s...", want_read ? "read" : "write");
+#ifdef ISCOMFITOR
+ if (want_read)
+ {
+ char buf[READBUFSIZ];
+ ssize_t len;
+ len = recv(svr->fd, buf, sizeof(buf), MSG_DONTWAIT | MSG_PEEK);
+ DBG("%zu bytes in buffer", len);
+ }
+#endif
+ if (ecore_con_ssl_server_init(svr))
+ {
+ ERR("ssl handshaking failed!");
+ svr->handshaking = EINA_FALSE;
+ }
+ else if (!svr->ssl_state)
+ ecore_con_event_server_add(svr);
+ return ECORE_CALLBACK_RENEW;
+ }
+ if (svr->ecs && svr->ecs_state && (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) && (!svr->ecs_buf))
+ {
+ if (svr->ecs_state < ECORE_CON_PROXY_STATE_INIT)
+ {
+ INF("PROXY STATE++");
+ svr->ecs_state++;
+ }
+ if (ecore_con_socks_svr_init(svr)) return ECORE_CALLBACK_RENEW;
+ }
+ if (want_read)
+ _ecore_con_cl_read(svr);
+ else if (want_write) /* only possible with non-ssl connections */
+ {
+ if (svr->connecting && (!svr_try_connect_plain(svr)) && (!svr->ecs_state))
+ return ECORE_CALLBACK_RENEW;
+
+ _ecore_con_server_flush(svr);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_con_cl_udp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ unsigned char buf[READBUFSIZ];
+ int num;
+ Ecore_Con_Server *svr;
+ Eina_Bool want_read, want_write;
+
+ want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ);
+ want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE);
+
+ svr = data;
+ if (svr->delete_me || ((!want_read) && (!want_write)))
+ return ECORE_CALLBACK_RENEW;
+
+ if (want_write)
+ {
+ _ecore_con_server_flush(svr);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ num = read(svr->fd, buf, READBUFSIZ);
+
+ if ((!svr->delete_me) && (num > 0))
+ ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+
+ if (num < 0 && (errno != EAGAIN) && (errno != EINTR))
+ {
+ ecore_con_event_server_error(svr, strerror(errno));
+ _ecore_con_server_kill(svr);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_con_svr_udp_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ unsigned char buf[READBUFSIZ];
+ unsigned char client_addr[256];
+ socklen_t client_addr_len = sizeof(client_addr);
+ int num;
+ Ecore_Con_Server *svr;
+ Ecore_Con_Client *cl = NULL;
+
+ svr = data;
+
+ if (svr->delete_me)
+ return ECORE_CALLBACK_RENEW;
+
+ if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
+ {
+ _ecore_con_client_flush(cl);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+ return ECORE_CALLBACK_RENEW;
+
+#ifdef _WIN32
+ num = fcntl(svr->fd, F_SETFL, O_NONBLOCK);
+ if (num >= 0)
+ num = recvfrom(svr->fd, (char *)buf, sizeof(buf), 0,
+ (struct sockaddr *)&client_addr,
+ &client_addr_len);
+
+#else
+ num = recvfrom(svr->fd, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *)&client_addr,
+ &client_addr_len);
+#endif
+
+ if (num < 0 && (errno != EAGAIN) && (errno != EINTR))
+ {
+ ecore_con_event_server_error(svr, strerror(errno));
+ if (!svr->delete_me)
+ ecore_con_event_client_del(NULL);
+ _ecore_con_server_kill(svr);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+
+/* Create a new client for use in the client data event */
+ cl = calloc(1, sizeof(Ecore_Con_Client));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cl, ECORE_CALLBACK_RENEW);
+
+ cl->host_server = svr;
+ cl->client_addr = malloc(client_addr_len);
+ if (!cl->client_addr)
+ {
+ free(cl);
+ return ECORE_CALLBACK_RENEW;
+ }
+ cl->client_addr_len = client_addr_len;
+
+ memcpy(cl->client_addr, &client_addr, client_addr_len);
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+ svr->clients = eina_list_append(svr->clients, cl);
+ svr->client_count++;
+
+ ecore_con_event_client_add(cl);
+ ecore_con_event_client_data(cl, buf, num, EINA_TRUE);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_con_svr_cl_read(Ecore_Con_Client *cl)
+{
+ int num = 0;
+ Eina_Bool lost_client = EINA_TRUE;
+ unsigned char buf[READBUFSIZ];
+
+ DBG("cl=%p", cl);
+
+ if (cl->handshaking)
+ {
+ /* add an extra handshake attempt just before read, even though
+ * read also attempts to handshake, to try to finish sooner
+ */
+ if (ecore_con_ssl_client_init(cl))
+ lost_client = EINA_FALSE;
+
+ _ecore_con_cl_timer_update(cl);
+ }
+
+ if (!(cl->host_server->type & ECORE_CON_SSL) && (!cl->upgrade))
+ {
+ num = read(cl->fd, buf, sizeof(buf));
+ /* 0 is not a valid return value for a tcp socket */
+ if ((num > 0) || ((num < 0) && ((errno == EAGAIN) || (errno == EINTR))))
+ lost_client = EINA_FALSE;
+ else if (num < 0)
+ ecore_con_event_client_error(cl, strerror(errno));
+ }
+ else
+ {
+ num = ecore_con_ssl_client_read(cl, buf, sizeof(buf));
+ /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */
+ if (num >= 0)
+ lost_client = EINA_FALSE;
+ }
+
+ if ((!cl->delete_me) && (num > 0))
+ ecore_con_event_client_data(cl, buf, num, EINA_TRUE);
+
+ if (lost_client) _ecore_con_client_kill(cl);
+}
+
+static Eina_Bool
+_ecore_con_svr_cl_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ Ecore_Con_Client *cl;
+
+ cl = data;
+ if (cl->delete_me)
+ return ECORE_CALLBACK_RENEW;
+
+ if (cl->handshaking && ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ | ECORE_FD_WRITE))
+ {
+ if (ecore_con_ssl_client_init(cl))
+ {
+ ERR("ssl handshaking failed!");
+ _ecore_con_client_kill(cl);
+ return ECORE_CALLBACK_RENEW;
+ }
+ else if (!cl->ssl_state)
+ ecore_con_event_client_add(cl);
+ }
+ else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+ _ecore_con_svr_cl_read(cl);
+
+ else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
+ _ecore_con_client_flush(cl);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_con_server_flush(Ecore_Con_Server *svr)
+{
+ int count, num;
+ size_t buf_len, buf_offset;
+ const unsigned char *buf;
+
+ DBG("(svr=%p,buf=%p)", svr, svr->buf);
+#ifdef _WIN32
+ if (ecore_con_local_win32_server_flush(svr))
+ return;
+#endif
+
+ if ((!svr->buf) && (!svr->ecs_buf) && svr->fd_handler)
+ {
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ return;
+ }
+
+ buf = svr->buf ? eina_binbuf_string_get(svr->buf) : eina_binbuf_string_get(svr->ecs_buf);
+ buf_len = svr->buf ? eina_binbuf_length_get(svr->buf) : eina_binbuf_length_get(svr->ecs_buf);
+ buf_offset = svr->buf ? svr->write_buf_offset : svr->ecs_buf_offset;
+ num = buf_len - buf_offset;
+
+ /* check whether we need to write anything at all.
+ * we must not write zero bytes with SSL_write() since it
+ * causes undefined behaviour
+ */
+ /* we thank Tommy[D] for needing to check negative buffer sizes
+ * here because his system is amazing.
+ */
+ if (num <= 0) return;
+
+ if ((!svr->ecs_state) && svr->handshaking)
+ {
+ DBG("Continuing ssl handshake");
+ if (ecore_con_ssl_server_init(svr))
+ _ecore_con_server_kill(svr);
+ _ecore_con_server_timer_update(svr);
+ return;
+ }
+
+ if (svr->ecs_state || (!(svr->type & ECORE_CON_SSL)))
+ count = write(svr->fd, buf + buf_offset, num);
+ else
+ count = ecore_con_ssl_server_write(svr, buf + buf_offset, num);
+
+ if (count < 0)
+ {
+ if ((errno != EAGAIN) && (errno != EINTR))
+ {
+ ecore_con_event_server_error(svr, strerror(errno));
+ _ecore_con_server_kill(svr);
+ }
+ return;
+ }
+
+ if (count && (!svr->ecs_state)) ecore_con_event_server_write(svr, count);
+ if (svr->ecs_buf)
+ buf_offset = svr->ecs_buf_offset += count;
+ else
+ buf_offset = svr->write_buf_offset += count;
+ if (buf_offset >= buf_len)
+ {
+ if (svr->ecs_buf)
+ {
+ svr->ecs_buf_offset = 0;
+ eina_binbuf_free(svr->ecs_buf);
+ svr->ecs_buf = NULL;
+ INF("PROXY STATE++");
+ svr->ecs_state++;
+ }
+ else
+ {
+ svr->write_buf_offset = 0;
+ eina_binbuf_free(svr->buf);
+ svr->buf = NULL;
+#ifdef TCP_CORK
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)
+ {
+ int state = 0;
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("uncorking failed! %s", strerror(errno));
+ }
+#endif
+ }
+ if (svr->fd_handler)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ }
+ else if ((count < num) && svr->fd_handler)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+}
+
+static void
+_ecore_con_client_flush(Ecore_Con_Client *cl)
+{
+ int num = 0, count = 0;
+
+#ifdef _WIN32
+ if (ecore_con_local_win32_client_flush(cl))
+ return;
+#endif
+
+ if (!cl->buf && cl->fd_handler)
+ {
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ return;
+ }
+
+ if (cl->handshaking)
+ {
+ if (ecore_con_ssl_client_init(cl))
+ count = -1;
+
+ _ecore_con_cl_timer_update(cl);
+ }
+
+ if (!count)
+ {
+ if (!cl->buf) return;
+ num = eina_binbuf_length_get(cl->buf) - cl->buf_offset;
+ if (num <= 0) return;
+ if (!(cl->host_server->type & ECORE_CON_SSL) && (!cl->upgrade))
+ count = write(cl->fd, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num);
+ else
+ count = ecore_con_ssl_client_write(cl, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num);
+ }
+
+ if (count < 0)
+ {
+ if ((errno != EAGAIN) && (errno != EINTR) && (!cl->delete_me))
+ {
+ ecore_con_event_client_error(cl, strerror(errno));
+ _ecore_con_client_kill(cl);
+ }
+
+ return;
+ }
+
+ if (count) ecore_con_event_client_write(cl, count);
+ cl->buf_offset += count, num -= count;
+ if (cl->buf_offset >= eina_binbuf_length_get(cl->buf))
+ {
+ cl->buf_offset = 0;
+ eina_binbuf_free(cl->buf);
+ cl->buf = NULL;
+#ifdef TCP_CORK
+ if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)
+ {
+ int state = 0;
+ if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("uncorking failed! %s", strerror(errno));
+ }
+#endif
+ if (cl->fd_handler)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ }
+ else if (cl->fd_handler && (num >= 0))
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
+}
+
+static void
+_ecore_con_event_client_add_free(Ecore_Con_Server *svr,
+ void *ev)
+{
+ Ecore_Con_Event_Client_Add *e;
+
+ e = ev;
+ if (e->client)
+ {
+ e->client->event_count = eina_list_remove(e->client->event_count, e);
+ if (e->client->host_server)
+ {
+ e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+ if ((!svr->event_count) && (svr->delete_me))
+ _ecore_con_server_free(svr);
+ }
+ if ((!e->client->event_count) && (e->client->delete_me))
+ ecore_con_client_del(e->client);
+ }
+
+ ecore_con_event_client_add_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_client_del_free(Ecore_Con_Server *svr,
+ void *ev)
+{
+ Ecore_Con_Event_Client_Del *e;
+
+ e = ev;
+ if (e->client)
+ {
+ e->client->event_count = eina_list_remove(e->client->event_count, e);
+ if (e->client->host_server)
+ {
+ e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+ if ((!svr->event_count) && (svr->delete_me))
+ _ecore_con_server_free(svr);
+ }
+ if (!e->client->event_count)
+ _ecore_con_client_free(e->client);
+ }
+ ecore_con_event_client_del_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_client_write_free(Ecore_Con_Server *svr,
+ Ecore_Con_Event_Client_Write *e)
+{
+ if (e->client)
+ {
+ e->client->event_count = eina_list_remove(e->client->event_count, e);
+ if (e->client->host_server)
+ {
+ e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, e);
+ if ((!svr->event_count) && (svr->delete_me))
+ _ecore_con_server_free(svr);
+ }
+ if (((!e->client->event_count) && (e->client->delete_me)) ||
+ ((e->client->host_server &&
+ ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP ||
+ (e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST))))
+ ecore_con_client_del(e->client);
+ }
+ ecore_con_event_client_write_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_client_data_free(Ecore_Con_Server *svr,
+ void *ev)
+{
+ Ecore_Con_Event_Client_Data *e;
+
+ e = ev;
+ if (e->client)
+ {
+ e->client->event_count = eina_list_remove(e->client->event_count, e);
+ if (e->client->host_server)
+ {
+ e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+ }
+ if ((!svr->event_count) && (svr->delete_me))
+ _ecore_con_server_free(svr);
+ if (((!e->client->event_count) && (e->client->delete_me)) ||
+ ((e->client->host_server &&
+ ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP ||
+ (e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST))))
+ ecore_con_client_del(e->client);
+ }
+ free(e->data);
+ ecore_con_event_client_data_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_server_add_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Con_Event_Server_Add *e;
+
+ e = ev;
+ if (e->server)
+ {
+ e->server->event_count = eina_list_remove(e->server->event_count, ev);
+ if ((!e->server->event_count) && (e->server->delete_me))
+ _ecore_con_server_free(e->server);
+ }
+ ecore_con_event_server_add_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_server_del_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Con_Event_Server_Del *e;
+
+ e = ev;
+ if (e->server)
+ {
+ e->server->event_count = eina_list_remove(e->server->event_count, ev);
+ if (!e->server->event_count)
+ _ecore_con_server_free(e->server);
+ }
+ ecore_con_event_server_del_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_server_write_free(void *data EINA_UNUSED,
+ Ecore_Con_Event_Server_Write *e)
+{
+ if (e->server)
+ {
+ e->server->event_count = eina_list_remove(e->server->event_count, e);
+ if ((!e->server->event_count) && (e->server->delete_me))
+ _ecore_con_server_free(e->server);
+ }
+
+ ecore_con_event_server_write_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_server_data_free(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Con_Event_Server_Data *e;
+
+ e = ev;
+ if (e->server)
+ {
+ e->server->event_count = eina_list_remove(e->server->event_count, ev);
+ if ((!e->server->event_count) && (e->server->delete_me))
+ _ecore_con_server_free(e->server);
+ }
+
+ free(e->data);
+ ecore_con_event_server_data_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+
+static void
+_ecore_con_event_server_error_free(void *data EINA_UNUSED, Ecore_Con_Event_Server_Error *e)
+{
+ if (e->server)
+ {
+ e->server->event_count = eina_list_remove(e->server->event_count, e);
+ if ((!e->server->event_count) && (e->server->delete_me))
+ _ecore_con_server_free(e->server);
+ }
+ free(e->error);
+ ecore_con_event_server_error_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_event_client_error_free(Ecore_Con_Server *svr, Ecore_Con_Event_Client_Error *e)
+{
+ if (e->client)
+ {
+ if (eina_list_data_find(svr->clients, e->client))
+ {
+ e->client->event_count = eina_list_remove(e->client->event_count, e);
+ if ((!e->client->event_count) && (e->client->delete_me))
+ _ecore_con_client_free(e->client);
+ }
+ svr->event_count = eina_list_remove(svr->event_count, e);
+ if ((!svr->event_count) && (svr->delete_me))
+ _ecore_con_server_free(svr);
+ }
+ free(e->error);
+ ecore_con_event_client_error_free(e);
+ _ecore_con_event_count--;
+ if ((!_ecore_con_event_count) && (!_ecore_con_init_count))
+ ecore_con_mempool_shutdown();
+}
+
+static void
+_ecore_con_lookup_done(void *data,
+ Ecore_Con_Info *infos)
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Lookup *lk;
+
+ svr = data;
+ lk = svr->data;
+
+ if (infos)
+ lk->done_cb(infos->info.ai_canonname, infos->ip,
+ infos->info.ai_addr, infos->info.ai_addrlen,
+ (void *)lk->data);
+ else
+ lk->done_cb(NULL, NULL, NULL, 0, (void *)lk->data);
+
+ free(svr->name);
+ free(lk);
+ free(svr);
+}
+
diff --git a/src/lib/ecore_con/ecore_con_alloc.c b/src/lib/ecore_con/ecore_con_alloc.c
new file mode 100644
index 0000000000..324d47d100
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_alloc.c
@@ -0,0 +1,101 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+typedef struct _Ecore_Con_Mempool Ecore_Con_Mempool;
+struct _Ecore_Con_Mempool
+{
+ const char *name;
+ Eina_Mempool *mp;
+ size_t size;
+};
+
+#define GENERIC_ALLOC_FREE(TYPE, Type) \
+ Ecore_Con_Mempool Type##_mp = { #TYPE, NULL, sizeof (TYPE) }; \
+ \
+ TYPE * \
+ Type##_alloc(void) \
+ { \
+ return eina_mempool_malloc(Type##_mp.mp, sizeof (TYPE)); \
+ } \
+ \
+ void \
+ Type##_free(TYPE *e) \
+ { \
+ eina_mempool_free(Type##_mp.mp, e); \
+ }
+
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Add, ecore_con_event_client_add);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Del, ecore_con_event_client_del);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Write, ecore_con_event_client_write);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Data, ecore_con_event_client_data);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Error, ecore_con_event_server_error);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Error, ecore_con_event_client_error);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Add, ecore_con_event_server_add);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Del, ecore_con_event_server_del);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Write, ecore_con_event_server_write);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Data, ecore_con_event_server_data);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind);
+
+static Ecore_Con_Mempool *mempool_array[] = {
+ &ecore_con_event_client_add_mp,
+ &ecore_con_event_client_del_mp,
+ &ecore_con_event_client_write_mp,
+ &ecore_con_event_client_data_mp,
+ &ecore_con_event_server_error_mp,
+ &ecore_con_event_client_error_mp,
+ &ecore_con_event_server_add_mp,
+ &ecore_con_event_server_del_mp,
+ &ecore_con_event_server_write_mp,
+ &ecore_con_event_server_data_mp,
+ &ecore_con_event_proxy_bind_mp
+};
+
+void
+ecore_con_mempool_init(void)
+{
+ const char *choice;
+ unsigned int i;
+
+ choice = getenv("EINA_MEMPOOL");
+ if (!choice || !choice[0])
+ choice = "chained_mempool";
+
+ for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i)
+ {
+ retry:
+ mempool_array[i]->mp = eina_mempool_add(choice, mempool_array[i]->name, NULL, mempool_array[i]->size, 16);
+ if (!mempool_array[i]->mp)
+ {
+ if (!(!strcmp(choice, "pass_through")))
+ {
+ ERR("Falling back to pass through ! Previously tried '%s' mempool.", choice);
+ choice = "pass_through";
+ goto retry;
+ }
+ else
+ {
+ ERR("Impossible to allocate mempool '%s' !", choice);
+ return ;
+ }
+ }
+ }
+}
+
+void
+ecore_con_mempool_shutdown(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i)
+ {
+ eina_mempool_del(mempool_array[i]->mp);
+ mempool_array[i]->mp = NULL;
+ }
+}
+
diff --git a/src/lib/ecore_con/ecore_con_ares.c b/src/lib/ecore_con/ecore_con_ares.c
new file mode 100644
index 0000000000..3c0ca22c85
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_ares.c
@@ -0,0 +1,628 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/*
+ * This version of ecore_con_info use c-ares to provide asynchronous dns lookup.
+ *
+ * Note: It doesn't fork nor does it use libc getaddrinfo.
+ * http://c-ares.haxx.se/docs.html
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#include <ares.h>
+
+#include "Ecore.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+typedef struct _Ecore_Con_FD Ecore_Con_FD;
+typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
+
+struct _Ecore_Con_FD
+{
+ Ecore_Fd_Handler *handler;
+ Ecore_Timer *timer;
+ int fd;
+};
+
+struct _Ecore_Con_CAres
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Info_Cb done_cb;
+ void *data;
+ struct addrinfo hints;
+ Ecore_Con_Info *result;
+
+ union {
+ struct in_addr v4;
+#ifdef HAVE_IPV6
+ struct in6_addr v6;
+#endif
+ } addr;
+
+ Eina_Bool byaddr : 1;
+ Eina_Bool isv6 : 1;
+};
+
+static ares_channel info_channel;
+static int info_init = 0;
+static Eina_List *info_fds = NULL;
+
+static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
+ int status,
+ int timeouts,
+ char *node,
+ char *service);
+static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
+ int status,
+ int timeouts,
+ struct hostent *hostent);
+static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
+
+static void
+_ecore_con_info_cares_state_cb(void *data,
+ ares_socket_t fd,
+ int readable,
+ int writable);
+static int
+_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
+ const Ecore_Con_FD *fd2);
+
+int
+ecore_con_info_init(void)
+{
+ struct ares_options opts;
+
+ if (!info_init)
+ {
+ if (ares_library_init(ARES_LIB_INIT_ALL))
+ return 0;
+
+ opts.lookups = "fb"; /* hosts file then dns */
+ opts.sock_state_cb = _ecore_con_info_cares_state_cb;
+
+ if (ares_init_options(&info_channel, &opts,
+ ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
+ {
+ ares_library_cleanup();
+ return 0;
+ }
+ }
+
+ info_init++;
+ return info_init;
+}
+
+int
+ecore_con_info_shutdown(void)
+{
+ info_init--;
+ if (info_init == 0)
+ {
+ /* Cancel all ongoing request */
+ ares_cancel(info_channel);
+ ares_destroy(info_channel);
+
+ /* Shutdown ares */
+ ares_library_cleanup();
+ }
+
+ return info_init;
+}
+
+int
+ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+static Eina_Bool
+_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
+ int addrtype,
+ const char *name,
+ struct sockaddr *addr,
+ int addrlen)
+{
+ int length = 0;
+
+ if (name)
+ length = strlen(name) + 1;
+ else
+ length = 1;
+
+ arg->result = malloc(sizeof(Ecore_Con_Info) + length);
+ if (!arg->result)
+ return EINA_FALSE;
+
+ /* FIXME: What to do when hint is not set ? */
+ arg->result->info.ai_flags = arg->hints.ai_flags;
+ arg->result->info.ai_socktype = arg->hints.ai_socktype;
+ arg->result->info.ai_protocol = arg->hints.ai_protocol;
+
+ arg->result->info.ai_family = addrtype;
+ arg->result->info.ai_addrlen = addrlen;
+ arg->result->info.ai_addr = addr;
+ arg->result->info.ai_canonname = (char *)(arg->result + 1);
+
+ if (!name)
+ *arg->result->info.ai_canonname = '\0';
+ else
+ strcpy(arg->result->info.ai_canonname, name);
+
+ arg->result->info.ai_next = NULL;
+
+ ares_getnameinfo(
+ info_channel, addr, addrlen,
+ ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
+ ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
+ (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
+
+ return EINA_TRUE;
+}
+
+EAPI int
+ecore_con_info_get(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data,
+ struct addrinfo *hints)
+{
+ Ecore_Con_CAres *cares;
+#ifdef HAVE_IPV6
+ int ai_family = AF_INET6;
+#else
+ int ai_family = AF_INET;
+#endif
+
+ cares = calloc(1, sizeof(Ecore_Con_CAres));
+ if (!cares)
+ return 0;
+
+ cares->svr = svr;
+ cares->done_cb = done_cb;
+ cares->data = data;
+
+ if (hints)
+ {
+ ai_family = hints->ai_family;
+ memcpy(&cares->hints, hints, sizeof(struct addrinfo));
+ }
+
+ if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
+ {
+ cares->byaddr = EINA_TRUE;
+ cares->isv6 = EINA_FALSE;
+ ares_gethostbyaddr(info_channel, &cares->addr.v4,
+ sizeof(cares->addr.v4),
+ AF_INET,
+ (ares_host_callback)_ecore_con_info_ares_host_cb,
+ cares);
+ }
+#ifdef HAVE_IPV6
+ else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
+ {
+ cares->byaddr = EINA_TRUE;
+ cares->isv6 = EINA_TRUE;
+ ares_gethostbyaddr(info_channel, &cares->addr.v6,
+ sizeof(cares->addr.v6),
+ AF_INET6,
+ (ares_host_callback)_ecore_con_info_ares_host_cb,
+ cares);
+ }
+#endif
+ else
+ {
+ cares->byaddr = EINA_FALSE;
+ ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family,
+ (ares_host_callback)_ecore_con_info_ares_host_cb,
+ cares);
+ }
+
+ svr->infos = eina_list_append(svr->infos, cares);
+ return 1;
+}
+
+void
+ecore_con_info_data_clear(void *info)
+{
+ Ecore_Con_CAres *cares = info;
+ if (cares) cares->data = NULL;
+}
+
+static Eina_Bool
+_ecore_con_info_cares_timeout_cb(void *data EINA_UNUSED)
+{
+ ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
+ Ecore_Fd_Handler *fd_handler)
+{
+ ares_socket_t read_fd, write_fd;
+
+ read_fd = write_fd = ARES_SOCKET_BAD;
+
+ if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+ read_fd = ecf->fd;
+ if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
+ write_fd = ecf->fd;
+
+ ares_process_fd(info_channel, read_fd, write_fd);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int
+_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
+ const Ecore_Con_FD *fd2)
+{
+ return fd1->fd - fd2->fd;
+}
+
+static void
+_ecore_con_info_cares_state_cb(void *data EINA_UNUSED,
+ ares_socket_t fd,
+ int readable,
+ int writable)
+{
+ int flags = 0;
+ Ecore_Con_FD *search = NULL, *ecf = NULL;
+
+ search = eina_list_search_unsorted(info_fds,
+ (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
+
+ if (!(readable | writable))
+ {
+ ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ if (search)
+ {
+ info_fds = eina_list_remove(info_fds, search);
+ ecore_timer_del(search->timer);
+ ecore_main_fd_handler_del(search->handler);
+ free(search);
+ }
+ return;
+ }
+
+ if (!search)
+ {
+ search = malloc(sizeof(Ecore_Con_FD));
+ EINA_SAFETY_ON_NULL_RETURN(search);
+
+ search->fd = fd;
+ search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ,
+ (Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL);
+ /* c-ares default timeout is 5 seconds */
+ search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL);
+ info_fds = eina_list_append(info_fds, search);
+ }
+
+ if (readable) flags |= ECORE_FD_READ;
+ if (writable) flags |= ECORE_FD_WRITE;
+ ecore_main_fd_handler_active_set(search->handler, flags);
+}
+
+static void
+_ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
+ int status,
+ int timeouts EINA_UNUSED,
+ struct hostent *hostent)
+{
+ struct sockaddr *addr;
+ int addrlen;
+
+ /* Found something ? */
+ switch (status)
+ {
+ case ARES_SUCCESS:
+ if (!hostent->h_addr_list[0])
+ {
+ ERR("No IP found");
+ goto on_error;
+ }
+
+ switch (hostent->h_addrtype)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *addri;
+
+ addrlen = sizeof(struct sockaddr_in);
+ addri = malloc(addrlen);
+
+ if (!addri)
+ goto on_mem_error;
+
+ addri->sin_family = AF_INET;
+ addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
+
+ memcpy(&addri->sin_addr.s_addr,
+ hostent->h_addr_list[0], sizeof(struct in_addr));
+
+ addr = (struct sockaddr *)addri;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *addri6;
+
+ addrlen = sizeof(struct sockaddr_in6);
+ addri6 = malloc(addrlen);
+
+ if (!addri6)
+ goto on_mem_error;
+
+ addri6->sin6_family = AF_INET6;
+ addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
+ addri6->sin6_flowinfo = 0;
+ addri6->sin6_scope_id = 0;
+
+ memcpy(&addri6->sin6_addr.s6_addr,
+ hostent->h_addr_list[0], sizeof(struct in6_addr));
+
+ addr = (struct sockaddr *)addri6;
+ break;
+ }
+#endif
+ default:
+ ERR("Unknown addrtype %i", hostent->h_addrtype);
+ goto on_error;
+ }
+
+ if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
+ hostent->h_name,
+ addr, addrlen))
+ goto on_error;
+
+ break;
+
+ case ARES_ENOTFOUND: /* address notfound */
+ if (arg->byaddr)
+ {
+#ifdef HAVE_IPV6
+ /* This happen when host doesn't have a reverse. */
+ if (arg->isv6)
+ {
+ struct sockaddr_in6 *addri6;
+
+ addrlen = sizeof(struct sockaddr_in6);
+ addri6 = malloc(addrlen);
+
+ if (!addri6)
+ goto on_mem_error;
+
+ addri6->sin6_family = AF_INET6;
+ addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
+ addri6->sin6_flowinfo = 0;
+ addri6->sin6_scope_id = 0;
+
+ memcpy(&addri6->sin6_addr.s6_addr,
+ &arg->addr.v6, sizeof(struct in6_addr));
+
+ addr = (struct sockaddr *)addri6;
+ }
+ else
+#endif
+ {
+ struct sockaddr_in *addri;
+
+ addrlen = sizeof(struct sockaddr_in);
+ addri = malloc(addrlen);
+
+ if (!addri)
+ goto on_mem_error;
+
+ addri->sin_family = AF_INET;
+ addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
+
+ memcpy(&addri->sin_addr.s_addr,
+ &arg->addr.v4, sizeof(struct in_addr));
+
+ addr = (struct sockaddr *)addri;
+ }
+
+ if (!_ecore_con_info_ares_getnameinfo(arg,
+#ifdef HAVE_IPV6
+ arg->isv6 ? AF_INET6 :
+#endif
+ AF_INET,
+ NULL, addr,
+ addrlen))
+ goto on_error;
+
+ break;
+ }
+
+ case ARES_ENOTIMP: /* unknown family */
+ case ARES_EBADNAME: /* not a valid internet address */
+ case ARES_ENOMEM: /* not enough memory */
+ case ARES_EDESTRUCTION: /* request canceled, shuting down */
+ case ARES_ENODATA: /* no data returned */
+ case ARES_ECONNREFUSED: /* connection refused */
+ case ARES_ETIMEOUT: /* connection timed out */
+ ecore_con_event_server_error(arg->svr, ares_strerror(status));
+ goto on_error;
+
+ default:
+ ERR("Unknown status returned by c-ares: %i assuming error", status);
+ ecore_con_event_server_error(arg->svr, ares_strerror(status));
+ goto on_error;
+ }
+
+ return;
+
+on_mem_error:
+ ERR("Not enough memory");
+
+on_error:
+ if (arg->data)
+ {
+ ecore_con_server_infos_del(arg->data, arg);
+ arg->done_cb(arg->data, NULL);
+ }
+ free(arg);
+}
+
+static void
+_ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
+ int status,
+ int timeouts EINA_UNUSED,
+ char *node,
+ char *service)
+{
+ switch (status)
+ {
+ case ARES_SUCCESS:
+ if (node)
+ strcpy(arg->result->ip, node);
+ else
+ *arg->result->ip = '\0';
+
+ if (service)
+ strcpy(arg->result->service, service);
+ else
+ *arg->result->service = '\0';
+
+ if (arg->data) arg->done_cb(arg->data, arg->result);
+ break;
+
+ case ARES_ENOTIMP:
+ case ARES_ENOTFOUND:
+ case ARES_ENOMEM:
+ case ARES_EDESTRUCTION:
+ case ARES_EBADFLAGS:
+ ecore_con_event_server_error(arg->svr, ares_strerror(status));
+ if (arg->data) arg->done_cb(arg->data, NULL);
+ break;
+ }
+
+ free(arg->result->info.ai_addr);
+ free(arg->result);
+ if (arg->data) ecore_con_server_infos_del(arg->data, arg);
+ free(arg);
+}
+
diff --git a/src/lib/ecore_con/ecore_con_dns.c b/src/lib/ecore_con/ecore_con_dns.c
new file mode 100644
index 0000000000..7851d0db82
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_dns.c
@@ -0,0 +1,344 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/*
+ * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup.
+ *
+ * dns.c is written by William Ahern:
+ * http://25thandclement.com/~william/projects/dns.c.html
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h> /* for EAGAIN */
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+#include "dns.h"
+
+#include "Ecore.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+typedef struct dns_addrinfo dns_addrinfo;
+typedef struct dns_resolv_conf dns_resolv_conf;
+typedef struct dns_resolver dns_resolver;
+typedef struct dns_hosts dns_hosts;
+
+typedef struct _Ecore_Con_DNS Ecore_Con_DNS;
+
+struct _Ecore_Con_DNS
+{
+ Ecore_Con_Server *svr;
+ Ecore_Con_Info_Cb done_cb;
+ void *data;
+ dns_addrinfo *ai;
+ dns_resolver *resolv;
+ struct addrinfo hints;
+ Ecore_Fd_Handler *fdh;
+ Ecore_Timer *timer;
+};
+
+static int _ecore_con_dns_init = 0;
+static dns_resolv_conf *resconf = NULL;
+static dns_hosts *hosts = NULL;
+
+static void
+_ecore_con_dns_free(Ecore_Con_DNS *dns)
+{
+ if (dns->svr->infos) dns->svr->infos = eina_list_remove(dns->svr->infos, dns);
+ if (dns->timer) ecore_timer_del(dns->timer);
+ if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
+ dns_res_close(dns_res_mortal(dns->resolv));
+ free(dns);
+}
+
+static Eina_Bool
+_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port)
+{
+ int error = 0;
+ char service[NI_MAXSERV];
+
+ snprintf(service, sizeof(service), "%d", port);
+ dns->ai = dns_ai_open(addr, service, DNS_T_A, (const struct addrinfo *)&dns->hints, dns->resolv, &error);
+ return error;
+}
+
+static int
+_ecore_con_dns_check(Ecore_Con_DNS *dns)
+{
+ struct addrinfo *ent = NULL;
+ int error = 0;
+
+ error = dns_ai_nextent(&ent, dns->ai);
+
+ switch (error)
+ {
+ case 0:
+ break;
+ case EAGAIN:
+ return 1;
+ default:
+ ERR("resolve failed: %s", dns_strerror(error));
+ goto error;
+ }
+
+ {
+ Ecore_Con_Info result = {0, .ip = {0}, .service = {0}};
+#if 0
+ char pretty[512];
+ dns_ai_print(pretty, sizeof(pretty), ent, dns->ai);
+ printf("%s\n", pretty);
+#endif
+ result.size = 0;
+ dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), result.ip, sizeof(result.ip));
+ snprintf(result.service, sizeof(result.service), "%u", ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)));
+ memcpy(&result.info, ent, sizeof(result.info));
+ if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
+ dns->fdh = NULL;
+ dns->done_cb(dns->data, &result);
+ free(ent);
+ _ecore_con_dns_free(dns);
+ }
+
+ return 0;
+error:
+ dns->done_cb(dns->data, NULL);
+ _ecore_con_dns_free(dns);
+ return -1;
+}
+
+static Eina_Bool
+_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh EINA_UNUSED)
+{
+ if (_ecore_con_dns_check(dns) != 1) return ECORE_CALLBACK_RENEW;
+ if (ecore_main_fd_handler_fd_get(dns->fdh) != dns_ai_pollfd(dns->ai))
+ {
+ ecore_main_fd_handler_del(dns->fdh);
+ dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
+ }
+ else
+ ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai));
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_dns_timer_cb(Ecore_Con_DNS *dns)
+{
+ dns->done_cb(dns->data, NULL);
+ _ecore_con_dns_free(dns);
+ dns->timer = NULL;
+ return EINA_FALSE;
+}
+
+int
+ecore_con_info_init(void)
+{
+ int err;
+ if (_ecore_con_dns_init) return ++_ecore_con_dns_init;
+
+ resconf = dns_resconf_local(&err);
+ if (!resconf)
+ {
+ ERR("resconf_open: %s", dns_strerror(err));
+ return 0;
+ }
+ hosts = dns_hosts_local(&err);
+ if (!hosts)
+ {
+ ERR("hosts_open: %s", dns_strerror(err));
+ dns_resconf_close(resconf);
+ resconf = NULL;
+ return 0;
+ }
+ /* this is super slow don't do it */
+ //resconf->options.recurse = 1;
+ return ++_ecore_con_dns_init;
+}
+
+int
+ecore_con_info_shutdown(void)
+{
+ if (!_ecore_con_dns_init) return 0;
+ if (--_ecore_con_dns_init) return _ecore_con_dns_init;
+ dns_resconf_close(resconf);
+ resconf = NULL;
+ dns_hosts_close(hosts);
+ hosts = NULL;
+ return 0;
+}
+
+void
+ecore_con_info_data_clear(void *info)
+{
+ Ecore_Con_DNS *dns = info;
+ if (dns) dns->data = NULL;
+}
+
+int
+ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+#ifdef HAVE_IPV6
+ hints.ai_family = AF_INET6;
+#else
+ hints.ai_family = AF_INET;
+#endif
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+EAPI int
+ecore_con_info_get(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data,
+ struct addrinfo *hints)
+{
+ Ecore_Con_DNS *dns;
+ int error = 0;
+
+ dns = calloc(1, sizeof(Ecore_Con_DNS));
+ if (!dns) return 0;
+
+ dns->svr = svr;
+ dns->done_cb = done_cb;
+ dns->data = data;
+
+ if (hints)
+ memcpy(&dns->hints, hints, sizeof(struct addrinfo));
+
+ if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error)))
+ {
+ ERR("res_open: %s", dns_strerror(error));
+ goto reserr;
+
+ }
+
+ error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, dns->svr->ecs ? dns->svr->ecs->port : dns->svr->port);
+ if (error && (error != EAGAIN))
+ {
+ ERR("resolver: %s", dns_strerror(error));
+ goto seterr;
+ }
+
+ switch (_ecore_con_dns_check(dns))
+ {
+ case 0:
+ break;
+ case 1:
+ dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL);
+ svr->infos = eina_list_append(svr->infos, dns);
+ dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+seterr:
+ if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv));
+reserr:
+ free(dns);
+ return 0;
+}
+
diff --git a/src/lib/ecore_con/ecore_con_eet.c b/src/lib/ecore_con/ecore_con_eet.c
new file mode 100644
index 0000000000..3a958f3663
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_eet.c
@@ -0,0 +1,822 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <Eina.h>
+
+#include "Ecore_Con_Eet.h"
+
+#define ECORE_CON_EET_RAW_MAGIC 0xDEAD007
+
+typedef struct _Ecore_Con_Eet_Data Ecore_Con_Eet_Data;
+typedef struct _Ecore_Con_Eet_Raw_Data Ecore_Con_Eet_Raw_Data;
+typedef struct _Ecore_Con_Eet_Client Ecore_Con_Eet_Client;
+typedef struct _Ecore_Con_Eet_Server Ecore_Con_Eet_Server;
+
+struct _Ecore_Con_Reply
+{
+ Ecore_Con_Eet *ece;
+ Ecore_Con_Client *client;
+
+ Eet_Connection *econn;
+
+ char *buffer_section;
+ unsigned char *buffer;
+ unsigned int buffer_length;
+ unsigned int buffer_current;
+ Ecore_Con_Eet_Raw_Data *buffer_handler;
+};
+
+struct _Ecore_Con_Eet_Data
+{
+ Ecore_Con_Eet_Data_Cb func;
+ const char *name;
+ const void *data;
+};
+
+struct _Ecore_Con_Eet_Raw_Data
+{
+ Ecore_Con_Eet_Raw_Data_Cb func;
+ const char *name;
+ const void *data;
+};
+
+struct _Ecore_Con_Eet_Client
+{
+ Ecore_Con_Eet_Client_Cb func;
+ const void *data;
+};
+
+struct _Ecore_Con_Eet_Server
+{
+ Ecore_Con_Eet_Server_Cb func;
+ const void *data;
+};
+
+struct _Ecore_Con_Eet
+{
+ Ecore_Con_Server *server;
+
+ Ecore_Event_Handler *handler_add;
+ Ecore_Event_Handler *handler_del;
+ Ecore_Event_Handler *handler_data;
+
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor *matching;
+
+ Eina_Hash *data_callbacks;
+ Eina_Hash *raw_data_callbacks;
+
+ union {
+ struct {
+ Eina_List *connections;
+ Eina_List *client_connect_callbacks;
+ Eina_List *client_disconnect_callbacks;
+ } server;
+ struct {
+ Ecore_Con_Reply *r;
+ Eina_List *server_connect_callbacks;
+ Eina_List *server_disconnect_callbacks;
+ } client;
+ } u;
+
+ const void *data;
+
+ Eina_Bool client : 1;
+};
+
+static void
+_ecore_con_eet_data_free(void *data)
+{
+ Ecore_Con_Eet_Data *eced = data;
+
+ eina_stringshare_del(eced->name);
+ free(eced);
+}
+
+static void
+_ecore_con_eet_raw_data_free(void *data)
+{
+ Ecore_Con_Eet_Raw_Data *eced = data;
+
+ eina_stringshare_del(eced->name);
+ free(eced);
+}
+static void
+_ecore_con_eet_reply_cleanup(Ecore_Con_Reply *n)
+{
+ if (n->buffer_handler) free(n->buffer);
+ n->buffer = NULL;
+ n->buffer_handler = NULL;
+ free(n->buffer_section);
+ n->buffer_section = NULL;
+}
+
+typedef struct _Ecore_Con_Eet_Protocol Ecore_Con_Eet_Protocol;
+struct _Ecore_Con_Eet_Protocol {
+ const char *type;
+ void *data;
+};
+
+static const char *
+_ecore_con_eet_data_type_get(const void *data, Eina_Bool *unknow EINA_UNUSED)
+{
+ const Ecore_Con_Eet_Protocol *p = data;
+
+ return p->type;
+}
+
+static Eina_Bool
+_ecore_con_eet_data_type_set(const char *type, void *data, Eina_Bool unknow EINA_UNUSED)
+{
+ Ecore_Con_Eet_Protocol *p = data;
+
+ p->type = type;
+ return EINA_TRUE;
+}
+
+static void
+_ecore_con_eet_data_descriptor_setup(Ecore_Con_Eet *ece)
+{
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Ecore_Con_Eet_Protocol);
+ ece->edd = eet_data_descriptor_stream_new(&eddc);
+
+ eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+ eddc.func.type_get = _ecore_con_eet_data_type_get;
+ eddc.func.type_set = _ecore_con_eet_data_type_set;
+ ece->matching = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_VARIANT(ece->edd, Ecore_Con_Eet_Protocol, "data", data, type, ece->matching);
+}
+
+/* Dealing with a server listening to connection */
+static Eina_Bool
+_ecore_con_eet_read_cb(const void *eet_data, size_t size, void *user_data)
+{
+ Ecore_Con_Reply *n = user_data;
+ Ecore_Con_Eet_Protocol *protocol;
+ Ecore_Con_Eet_Data *cb;
+
+ protocol = eet_data_descriptor_decode(n->ece->edd, eet_data, size);
+ if (!protocol) return EINA_TRUE;
+
+ cb = eina_hash_find(n->ece->data_callbacks, protocol->type);
+ if (!cb) return EINA_TRUE; /* Should I report unknow protocol communication ? */
+
+ cb->func((void*)cb->data, n, cb->name, protocol->data);
+
+ eina_stringshare_del(protocol->type);
+ free(protocol);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_server_write_cb(const void *data, size_t size, void *user_data)
+{
+ Ecore_Con_Reply *n = user_data;
+
+ if (ecore_con_client_send(n->client, data, size) != (int) size)
+ return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_client_write_cb(const void *data, size_t size, void *user_data)
+{
+ Ecore_Con_Reply *n = user_data;
+
+ if (ecore_con_server_send(n->ece->server, data, size) != (int) size)
+ return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_server_connected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Add *ev)
+{
+ Ecore_Con_Eet_Client *ecec;
+ Eina_List *ll;
+ Ecore_Con_Eet *r = data;
+ Ecore_Con_Reply *n;
+
+ if (ecore_con_client_server_get(ev->client) != r->server)
+ return EINA_TRUE;
+
+ n = calloc(1, sizeof (Ecore_Con_Reply));
+ if (!n) return EINA_TRUE;
+
+ n->client = ev->client;
+ n->ece = r;
+ n->econn = eet_connection_new(_ecore_con_eet_read_cb, _ecore_con_eet_server_write_cb, n);
+ ecore_con_client_data_set(n->client, n);
+
+ EINA_LIST_FOREACH(r->u.server.client_connect_callbacks, ll, ecec)
+ if (!ecec->func((void*) ecec->data, n, n->client))
+ {
+ eet_connection_close(n->econn, NULL);
+ free(n);
+ return EINA_TRUE;
+ }
+
+ r->u.server.connections = eina_list_append(r->u.server.connections, n);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_server_disconnected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Del *ev)
+{
+ Ecore_Con_Eet *r = data;
+ Ecore_Con_Reply *n;
+ Eina_List *l;
+
+ if (ecore_con_client_server_get(ev->client) != r->server)
+ return EINA_TRUE;
+
+ EINA_LIST_FOREACH(r->u.server.connections, l, n)
+ if (n->client == ev->client)
+ {
+ Ecore_Con_Eet_Client *ecec;
+ Eina_List *ll;
+
+ EINA_LIST_FOREACH(r->u.server.client_disconnect_callbacks, ll, ecec)
+ ecec->func((void*) ecec->data, n, n->client);
+
+ eet_connection_close(n->econn, NULL);
+ free(n);
+ r->u.server.connections = eina_list_remove_list(r->u.server.connections, l);
+ return EINA_TRUE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_con_eet_raw_data_push(Ecore_Con_Reply *n, void *data, int size)
+{
+ if (n->buffer_handler)
+ memcpy(n->buffer + n->buffer_current, data, size);
+ n->buffer_current += size;
+
+ if (n->buffer_current == n->buffer_length)
+ {
+ if (n->buffer_handler)
+ n->buffer_handler->func((void*) n->buffer_handler->data, n, n->buffer_handler->name, n->buffer_section, n->buffer, n->buffer_length);
+ _ecore_con_eet_reply_cleanup(n);
+ }
+}
+
+static void
+_ecore_con_eet_data(Ecore_Con_Reply *n, void *data, unsigned int size)
+{
+ /* FIXME: Enforce detection of attack and kill connection on that case */
+ if (n->buffer)
+ {
+ if (n->buffer_current + size > n->buffer_length)
+ {
+ _ecore_con_eet_reply_cleanup(n);
+ return ;
+ }
+
+ _ecore_con_eet_raw_data_push(n, data, size);
+ return ;
+ }
+ else if (eet_connection_empty(n->econn) && size > (int) (4 * sizeof (unsigned int) + 2))
+ {
+ unsigned int *tmp = data;
+ size -= 4 * sizeof (unsigned int) + 2;
+
+ if (ntohl(tmp[0]) == ECORE_CON_EET_RAW_MAGIC)
+ {
+ unsigned int protocol_length = ntohl(tmp[1]);
+ unsigned int section_length = ntohl(tmp[2]);
+ unsigned int data_length = ntohl(tmp[3]);
+
+ if (protocol_length > 1 && section_length > 1 && protocol_length + section_length <= size && data_length < 10 * 1024 * 1024)
+ {
+ char *buffer = (char*) &tmp[4];
+ char *protocol;
+ char *section;
+
+ protocol = buffer;
+ section = buffer + protocol_length;
+
+ if (protocol[protocol_length - 1] == '\0' &&
+ section[section_length - 1] == '\0')
+ {
+ size -= protocol_length + section_length;
+ buffer = section + section_length;
+
+ n->buffer_handler = eina_hash_find(n->ece->raw_data_callbacks, protocol);
+ n->buffer_section = strdup(section);
+ n->buffer_length = data_length;
+ n->buffer_current = 0;
+ if (n->buffer_handler)
+ n->buffer = malloc(sizeof (data_length));
+ else
+ n->buffer = (void*) 1;
+ if (n->buffer)
+ {
+ _ecore_con_eet_raw_data_push(n, buffer, size);
+ return ;
+ }
+ _ecore_con_eet_reply_cleanup(n);
+
+ size += protocol_length + section_length;
+ }
+ }
+ }
+
+ size += 4 * sizeof (unsigned int) + 2;
+ }
+
+ eet_connection_received(n->econn, data, size);
+}
+
+static Eina_Bool
+_ecore_con_eet_server_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Data *ev)
+{
+ Ecore_Con_Eet *r = data;
+ Ecore_Con_Reply *n;
+
+ if (ecore_con_client_server_get(ev->client) != r->server)
+ return EINA_TRUE;
+
+ n = ecore_con_client_data_get(ev->client);
+
+ _ecore_con_eet_data(n, ev->data, ev->size);
+
+ return EINA_TRUE;
+}
+
+/* Dealing connection to a server */
+
+static Eina_Bool
+_ecore_con_eet_client_connected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Add *ev)
+{
+ Ecore_Con_Eet_Server *eces;
+ Ecore_Con_Eet *r = data;
+ Ecore_Con_Reply *n;
+ Eina_List *ll;
+
+ /* Client did connect */
+ if (r->server != ev->server) return EINA_TRUE;
+ if (r->u.client.r) return EINA_TRUE;
+
+ n = calloc(1, sizeof (Ecore_Con_Reply));
+ if (!n) return EINA_TRUE;
+
+ n->client = NULL;
+ n->ece = r;
+ n->econn = eet_connection_new(_ecore_con_eet_read_cb, _ecore_con_eet_client_write_cb, n);
+
+ EINA_LIST_FOREACH(r->u.client.server_connect_callbacks, ll, eces)
+ if (!eces->func((void*) eces->data, n, n->ece->server))
+ {
+ eet_connection_close(n->econn, NULL);
+ free(n);
+ return EINA_TRUE;
+ }
+
+ r->u.client.r = n;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_client_disconnected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Del *ev)
+{
+ Ecore_Con_Eet *r = data;
+ Ecore_Con_Eet_Server *eces;
+ Eina_List *ll;
+
+ if (r->server != ev->server) return EINA_TRUE;
+ if (!r->u.client.r) return EINA_TRUE;
+
+ /* Client disconnected */
+ EINA_LIST_FOREACH(r->u.client.server_disconnect_callbacks, ll, eces)
+ eces->func((void*) eces->data, r->u.client.r, r->server);
+
+ eet_connection_close(r->u.client.r->econn, NULL);
+ free(r->u.client.r);
+ r->u.client.r = NULL;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_eet_client_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Data *ev)
+{
+ Ecore_Con_Eet *r = data;
+
+ if (r->server != ev->server) return EINA_TRUE;
+ if (!r->u.client.r) return EINA_TRUE;
+
+ /* Got some data */
+ _ecore_con_eet_data(r->u.client.r, ev->data, ev->size);
+
+ return EINA_TRUE;
+}
+
+/**************
+ * Global API *
+ **************/
+
+EAPI Ecore_Con_Eet *
+ecore_con_eet_server_new(Ecore_Con_Server *server)
+{
+ Ecore_Con_Eet *r;
+
+ if (!server) return NULL;
+
+ r = calloc(1, sizeof (Ecore_Con_Eet));
+ if (!r) return NULL;
+
+ r->server = server;
+ r->handler_add = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_server_connected, r);
+ r->handler_del = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_server_disconnected, r);
+ r->handler_data = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_server_data, r);
+ r->data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_data_free);
+ r->raw_data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_raw_data_free);
+
+ _ecore_con_eet_data_descriptor_setup(r);
+
+ return r;
+}
+
+EAPI Ecore_Con_Eet *
+ecore_con_eet_client_new(Ecore_Con_Server *server)
+{
+ Ecore_Con_Eet *r;
+
+ if (!server) return NULL;
+
+ r = calloc(1, sizeof (Ecore_Con_Eet));
+ if (!r) return NULL;
+
+ r->client = EINA_TRUE;
+ r->server = server;
+ r->handler_add = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_client_connected, r);
+ r->handler_del = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_client_disconnected, r);
+ r->handler_data = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
+ (Ecore_Event_Handler_Cb)_ecore_con_eet_client_data, r);
+ r->data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_data_free);
+ r->raw_data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_raw_data_free);
+
+ _ecore_con_eet_data_descriptor_setup(r);
+
+ return r;
+}
+
+EAPI void
+ecore_con_eet_server_free(Ecore_Con_Eet *r)
+{
+ if (!r) return ;
+
+ eet_data_descriptor_free(r->edd);
+ eet_data_descriptor_free(r->matching);
+ eina_hash_free(r->data_callbacks);
+ eina_hash_free(r->raw_data_callbacks);
+
+ if (r->client)
+ {
+ Ecore_Con_Eet_Server *s;
+
+ if (r->u.client.r)
+ {
+ _ecore_con_eet_reply_cleanup(r->u.client.r);
+ eet_connection_close(r->u.client.r->econn, NULL);
+ free(r->u.client.r);
+ }
+ EINA_LIST_FREE(r->u.client.server_connect_callbacks, s)
+ free(s);
+ EINA_LIST_FREE(r->u.client.server_disconnect_callbacks, s)
+ free(s);
+ }
+ else
+ {
+ Ecore_Con_Reply *n;
+ Ecore_Con_Eet_Client *c;
+
+ EINA_LIST_FREE(r->u.server.connections, n)
+ {
+ _ecore_con_eet_reply_cleanup(n);
+ eet_connection_close(n->econn, NULL);
+ free(n);
+ }
+ EINA_LIST_FREE(r->u.server.client_connect_callbacks, c)
+ free(c);
+ EINA_LIST_FREE(r->u.server.client_disconnect_callbacks, c)
+ free(c);
+ }
+
+ ecore_event_handler_del(r->handler_add);
+ ecore_event_handler_del(r->handler_del);
+ ecore_event_handler_del(r->handler_data);
+ free(r);
+}
+
+EAPI void
+ecore_con_eet_register(Ecore_Con_Eet *ece, const char *name, Eet_Data_Descriptor *edd)
+{
+ if (!ece) return ;
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(ece->matching, name, edd);
+}
+
+EAPI void
+ecore_con_eet_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Data_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Data *eced;
+
+ if (!ece) return ;
+
+ eced = calloc(1, sizeof (Ecore_Con_Eet_Data));;
+ if (!eced) return ;
+
+ eced->func = func;
+ eced->data = data;
+ eced->name = eina_stringshare_add(name);
+
+ eina_hash_direct_add(ece->data_callbacks, eced->name, eced);
+}
+
+EAPI void
+ecore_con_eet_data_callback_del(Ecore_Con_Eet *ece, const char *name)
+{
+ if (!ece) return ;
+ eina_hash_del(ece->data_callbacks, name, NULL);
+}
+
+EAPI void
+ecore_con_eet_raw_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Raw_Data_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Raw_Data *eced;
+
+ if (!ece) return ;
+
+ eced = calloc(1, sizeof (Ecore_Con_Eet_Raw_Data));;
+ if (!eced) return ;
+
+ eced->func = func;
+ eced->data = data;
+ eced->name = eina_stringshare_add(name);
+
+ eina_hash_direct_add(ece->raw_data_callbacks, eced->name, eced);
+}
+
+EAPI void
+ecore_con_eet_raw_data_callback_del(Ecore_Con_Eet *ece, const char *name)
+{
+ if (!ece) return ;
+
+ if (ece->client && ece->u.client.r->buffer_handler && !strcmp(ece->u.client.r->buffer_handler->name, name))
+ {
+ ece->u.client.r->buffer_handler = NULL;
+ free(ece->u.client.r->buffer);
+ ece->u.client.r->buffer = (void*) 1;
+ }
+ eina_hash_del(ece->raw_data_callbacks, name, NULL);
+}
+
+EAPI void
+ecore_con_eet_client_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Client *c;
+
+ if (!ece || !func) return ;
+
+ c = calloc(1, sizeof (Ecore_Con_Eet_Client));
+ if (!c) return ;
+
+ c->func = func;
+ c->data = data;
+
+ ece->u.server.client_connect_callbacks = eina_list_append(ece->u.server.client_connect_callbacks, c);
+}
+
+EAPI void
+ecore_con_eet_client_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Client *c;
+ Eina_List *l;
+
+ if (!ece || !func) return ;
+
+ EINA_LIST_FOREACH(ece->u.server.client_connect_callbacks, l, c)
+ if (c->func == func && c->data == data)
+ {
+ ece->u.server.client_connect_callbacks = eina_list_remove_list(ece->u.server.client_connect_callbacks, l);
+ free(c);
+ return ;
+ }
+}
+
+EAPI void
+ecore_con_eet_client_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Client *c;
+
+ if (!ece || !func) return ;
+
+ c = calloc(1, sizeof (Ecore_Con_Eet_Client));
+ if (!c) return ;
+
+ c->func = func;
+ c->data = data;
+
+ ece->u.server.client_connect_callbacks = eina_list_append(ece->u.server.client_disconnect_callbacks, c);
+}
+
+EAPI void
+ecore_con_eet_client_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Client *c;
+ Eina_List *l;
+
+ if (!ece || !func) return ;
+
+ EINA_LIST_FOREACH(ece->u.server.client_disconnect_callbacks, l, c)
+ if (c->func == func && c->data == data)
+ {
+ ece->u.server.client_disconnect_callbacks = eina_list_remove_list(ece->u.server.client_disconnect_callbacks,
+ l);
+ free(c);
+ return ;
+ }
+}
+
+EAPI void
+ecore_con_eet_server_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Server *s;
+
+ if (!ece || !func) return ;
+
+ s = calloc(1, sizeof (Ecore_Con_Eet_Server));
+ if (!s) return ;
+
+ s->func = func;
+ s->data = data;
+
+ ece->u.client.server_connect_callbacks = eina_list_append(ece->u.client.server_connect_callbacks, s);
+}
+
+EAPI void
+ecore_con_eet_server_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Server *s;
+ Eina_List *l;
+
+ if (!ece || !func) return ;
+
+ EINA_LIST_FOREACH(ece->u.client.server_connect_callbacks, l, s)
+ if (s->func == func && s->data == data)
+ {
+ ece->u.client.server_connect_callbacks = eina_list_remove_list(ece->u.client.server_connect_callbacks, l);
+ free(s);
+ return ;
+ }
+}
+
+EAPI void
+ecore_con_eet_server_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Server *s;
+
+ if (!ece || !func) return ;
+
+ s = calloc(1, sizeof (Ecore_Con_Eet_Server));
+ if (!s) return ;
+
+ s->func = func;
+ s->data = data;
+
+ ece->u.client.server_disconnect_callbacks = eina_list_append(ece->u.client.server_disconnect_callbacks, s);
+}
+
+EAPI void
+ecore_con_eet_server_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data)
+{
+ Ecore_Con_Eet_Server *s;
+ Eina_List *l;
+
+ if (!ece || !func) return ;
+
+ EINA_LIST_FOREACH(ece->u.client.server_disconnect_callbacks, l, s)
+ if (s->func == func && s->data == data)
+ {
+ ece->u.client.server_disconnect_callbacks = eina_list_remove_list(ece->u.client.server_disconnect_callbacks, l);
+ free(s);
+ return ;
+ }
+}
+
+EAPI void
+ecore_con_eet_data_set(Ecore_Con_Eet *ece, const void *data)
+{
+ if (!ece) return;
+
+ ece->data = data;
+}
+
+EAPI void *
+ecore_con_eet_data_get(Ecore_Con_Eet *ece)
+{
+ if (!ece) return NULL;
+ return (void*) ece->data;
+}
+
+EAPI Ecore_Con_Eet *
+ecore_con_eet_reply(Ecore_Con_Reply *reply)
+{
+ if (!reply) return NULL;
+ return reply->ece;
+}
+
+EAPI void
+ecore_con_eet_send(Ecore_Con_Reply *reply, const char *name, void *value)
+{
+ Ecore_Con_Eet_Protocol protocol;
+
+ if (!reply) return ;
+
+ protocol.type = name;
+ protocol.data = value;
+
+ eet_connection_send(reply->econn, reply->ece->edd, &protocol, NULL);
+}
+
+EAPI void
+ecore_con_eet_raw_send(Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, unsigned int length)
+{
+ unsigned int protocol[4];
+ unsigned int protocol_length;
+ unsigned int section_length;
+ unsigned int size;
+ char *tmp;
+
+ if (!reply) return ;
+ if (!protocol_name) return ;
+ if (!section) return ;
+
+ protocol_length = strlen(protocol_name) + 1;
+ if (protocol_length == 1) return ;
+ section_length = strlen(section) + 1;
+
+ protocol[0] = htonl(ECORE_CON_EET_RAW_MAGIC);
+ protocol[1] = htonl(protocol_length);
+ protocol[2] = htonl(section_length);
+ protocol[3] = htonl(length);
+
+ size = sizeof (protocol) + protocol_length + section_length;
+ tmp = alloca(size);
+ memcpy(tmp, protocol, sizeof (protocol));
+ memcpy(tmp + sizeof (protocol), protocol, protocol_length);
+ memcpy(tmp + sizeof (protocol) + protocol_length, section, section_length);
+
+ if (reply->client)
+ {
+ ecore_con_client_send(reply->client, tmp, size);
+ ecore_con_client_send(reply->client, value, length);
+ }
+ else
+ {
+ ecore_con_server_send(reply->ece->server, tmp, size);
+ ecore_con_server_send(reply->ece->server, value, length);
+ }
+}
+
diff --git a/src/lib/ecore_con/ecore_con_info.c b/src/lib/ecore_con/ecore_con_info.c
new file mode 100644
index 0000000000..80e199a411
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_info.c
@@ -0,0 +1,458 @@
+/*
+ * getaddrinfo with callback
+ *
+ * man getaddrinfo
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifdef __OpenBSD__
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#include <errno.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_con_private.h"
+
+typedef struct _CB_Data CB_Data;
+
+struct _CB_Data
+{
+ EINA_INLIST;
+ Ecore_Con_Info_Cb cb_done;
+ void *data;
+ Ecore_Fd_Handler *fdh;
+ pid_t pid;
+ Ecore_Event_Handler *handler;
+ int fd2;
+};
+
+static void _ecore_con_info_readdata(CB_Data *cbdata);
+static void _ecore_con_info_slave_free(CB_Data *cbdata);
+static Eina_Bool _ecore_con_info_data_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_info_exit_handler(void *data,
+ int type EINA_UNUSED,
+ void *event);
+
+static int info_init = 0;
+static CB_Data *info_slaves = NULL;
+
+int
+ecore_con_info_init(void)
+{
+ info_init++;
+ return info_init;
+}
+
+int
+ecore_con_info_shutdown(void)
+{
+ info_init--;
+ if (info_init == 0)
+ while (info_slaves) _ecore_con_info_slave_free(info_slaves);
+
+ return info_init;
+}
+
+int
+ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_udp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+int
+ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data)
+{
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return ecore_con_info_get(svr, done_cb, data, &hints);
+}
+
+EAPI int
+ecore_con_info_get(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data,
+ struct addrinfo *hints)
+{
+ CB_Data *cbdata;
+ int fd[2];
+
+ if (pipe(fd) < 0)
+ {
+ ecore_con_event_server_error(svr, strerror(errno));
+ return 0;
+ }
+
+ cbdata = calloc(1, sizeof(CB_Data));
+ if (!cbdata)
+ {
+ close(fd[0]);
+ close(fd[1]);
+ return 0;
+ }
+
+ cbdata->cb_done = done_cb;
+ cbdata->data = data;
+ cbdata->fd2 = fd[1];
+ if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ,
+ _ecore_con_info_data_handler,
+ cbdata,
+ NULL, NULL)))
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure");
+ free(cbdata);
+ close(fd[0]);
+ close(fd[1]);
+ return 0;
+ }
+
+ if ((cbdata->pid = fork()) == 0)
+ {
+ Ecore_Con_Info *container;
+ struct addrinfo *result = NULL;
+ char service[NI_MAXSERV] = {0};
+ char hbuf[NI_MAXHOST] = {0};
+ char sbuf[NI_MAXSERV] = {0};
+ unsigned char *tosend = NULL;
+ int tosend_len;
+ int canonname_len = 0;
+
+ eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service);
+ /* CHILD */
+ if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result)
+ {
+ if (result->ai_canonname)
+ canonname_len = strlen(result->ai_canonname) + 1;
+
+ tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
+ canonname_len;
+
+ tosend = alloca(tosend_len);
+ memset(tosend, 0, tosend_len);
+
+ container = (Ecore_Con_Info *)tosend;
+ container->size = tosend_len;
+
+ memcpy(&container->info,
+ result,
+ sizeof(struct addrinfo));
+ memcpy(tosend + sizeof(Ecore_Con_Info),
+ result->ai_addr,
+ result->ai_addrlen);
+ if (result->ai_canonname) /* FIXME: else... */
+ memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
+ result->ai_canonname,
+ canonname_len);
+
+ if (!getnameinfo(result->ai_addr, result->ai_addrlen,
+ hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ {
+ memcpy(container->ip, hbuf, sizeof(container->ip));
+ memcpy(container->service, sbuf, sizeof(container->service));
+ }
+
+ if (write(fd[1], tosend, tosend_len) < 0) perror("write");
+ }
+
+ if (result)
+ freeaddrinfo(result);
+
+ if (write(fd[1], "", 1) < 0) perror("write");
+ close(fd[1]);
+#if defined(__USE_ISOC99) && !defined(__UCLIBC__)
+ _Exit(0);
+#else
+ _exit(0);
+#endif
+ }
+
+ /* PARENT */
+ cbdata->handler =
+ ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
+ cbdata);
+ close(fd[1]);
+ if (!cbdata->handler)
+ {
+ ecore_main_fd_handler_del(cbdata->fdh);
+ free(cbdata);
+ close(fd[0]);
+ return 0;
+ }
+
+ info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
+ info_slaves),
+ EINA_INLIST_GET(cbdata));
+ svr->infos = eina_list_append(svr->infos, cbdata);
+ return 1;
+}
+
+void
+ecore_con_info_data_clear(void *info)
+{
+ CB_Data *cbdata = info;
+ cbdata->data = NULL;
+}
+
+static void
+_ecore_con_info_readdata(CB_Data *cbdata)
+{
+ Ecore_Con_Info container;
+ Ecore_Con_Info *recv_info;
+ unsigned char *torecv;
+ int torecv_len;
+
+ ssize_t size;
+
+ size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
+ sizeof(Ecore_Con_Info));
+ if (size == sizeof(Ecore_Con_Info))
+ {
+ torecv_len = container.size;
+ torecv = malloc(torecv_len);
+
+ memcpy(torecv, &container, sizeof(Ecore_Con_Info));
+
+ size = read(ecore_main_fd_handler_fd_get(cbdata->fdh),
+ torecv + sizeof(Ecore_Con_Info),
+ torecv_len - sizeof(Ecore_Con_Info));
+ if ((size > 0) &&
+ ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
+ {
+ recv_info = (Ecore_Con_Info *)torecv;
+
+ recv_info->info.ai_addr =
+ (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
+ if ((size_t)torecv_len !=
+ (sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen))
+ recv_info->info.ai_canonname = (char *)
+ (torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen);
+ else
+ recv_info->info.ai_canonname = NULL;
+
+ recv_info->info.ai_next = NULL;
+
+ if (cbdata->data)
+ {
+ cbdata->cb_done(cbdata->data, recv_info);
+ ecore_con_server_infos_del(cbdata->data, cbdata);
+ }
+
+ free(torecv);
+ }
+ else
+ {
+ if (cbdata->data)
+ {
+ cbdata->cb_done(cbdata->data, NULL);
+ ecore_con_server_infos_del(cbdata->data, cbdata);
+ }
+ }
+ }
+ else
+ {
+ if (cbdata->data)
+ {
+ ecore_con_event_server_error(cbdata->data, strerror(errno));
+ cbdata->cb_done(cbdata->data, NULL);
+ ecore_con_server_infos_del(cbdata->data, cbdata);
+ }
+ }
+
+ cbdata->cb_done = NULL;
+}
+
+static void
+_ecore_con_info_slave_free(CB_Data *cbdata)
+{
+ info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
+ EINA_INLIST_GET(cbdata));
+ ecore_main_fd_handler_del(cbdata->fdh);
+ ecore_event_handler_del(cbdata->handler);
+ close(ecore_main_fd_handler_fd_get(cbdata->fdh));
+ if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
+ free(cbdata);
+}
+
+static Eina_Bool
+_ecore_con_info_data_handler(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ CB_Data *cbdata;
+
+ cbdata = data;
+ if (cbdata->cb_done)
+ {
+ if (ecore_main_fd_handler_active_get(fd_handler,
+ ECORE_FD_READ))
+ _ecore_con_info_readdata(cbdata);
+ else
+ {
+ if (cbdata->data)
+ {
+ cbdata->cb_done(cbdata->data, NULL);
+ cbdata->cb_done = NULL;
+ ecore_con_server_infos_del(cbdata->data, cbdata);
+ }
+ }
+ }
+
+ _ecore_con_info_slave_free(cbdata);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_con_info_exit_handler(void *data,
+ int type EINA_UNUSED,
+ void *event)
+{
+ CB_Data *cbdata;
+ Ecore_Exe_Event_Del *ev;
+
+ ev = event;
+ cbdata = data;
+ if (cbdata->pid != ev->pid)
+ return ECORE_CALLBACK_RENEW;
+
+ return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
+ _ecore_con_info_slave_free(cbdata);
+ return ECORE_CALLBACK_CANCEL;
+}
+
diff --git a/src/lib/ecore_con/ecore_con_local.c b/src/lib/ecore_con/ecore_con_local.c
new file mode 100644
index 0000000000..fff0059d66
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_local.c
@@ -0,0 +1,325 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#include <Ecore.h>
+#include <ecore_private.h>
+
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + \
+ (size_t)(((struct sockaddr_un *)NULL)-> \
+ sun_path))
+#define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 + \
+ (size_t)(((struct sockaddr_un \
+ *)NULL)->sun_path))
+
+static int _ecore_con_local_init_count = 0;
+
+int
+ecore_con_local_init(void)
+{
+ if (++_ecore_con_local_init_count != 1)
+ return _ecore_con_local_init_count;
+
+ return _ecore_con_local_init_count;
+}
+
+int
+ecore_con_local_shutdown(void)
+{
+ if (--_ecore_con_local_init_count != 0)
+ return _ecore_con_local_init_count;
+
+ return _ecore_con_local_init_count;
+}
+
+int
+ecore_con_local_connect(Ecore_Con_Server *svr,
+ Eina_Bool (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler),
+ void *data EINA_UNUSED)
+{
+#ifndef HAVE_LOCAL_SOCKETS
+ return 0;
+#else
+ char buf[4096];
+ struct sockaddr_un socket_unix;
+ int curstate = 0;
+ const char *homedir;
+ int socket_unix_len;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
+ {
+ homedir = getenv("HOME");
+ if (!homedir)
+ homedir = getenv("TMP");
+
+ if (!homedir)
+ homedir = "/tmp";
+
+ snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name,
+ svr->port);
+ }
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
+ {
+ if (svr->port < 0)
+ {
+ if (svr->name[0] == '/')
+ strncpy(buf, svr->name, sizeof(buf));
+ else
+ snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", svr->name);
+ }
+ else
+ {
+ if (svr->name[0] ==
+ '/')
+ snprintf(buf, sizeof(buf), "%s|%i", svr->name,
+ svr->port);
+ else
+ snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i",
+ svr->name,
+ svr->port);
+ }
+ }
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ strncpy(buf, svr->name,
+ sizeof(buf));
+
+ svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (svr->fd < 0)
+ return 0;
+
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
+ return 0;
+
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
+ return 0;
+
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
+ sizeof(curstate)) < 0)
+ return 0;
+
+ socket_unix.sun_family = AF_UNIX;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ {
+#ifdef HAVE_ABSTRACT_SOCKETS
+ /* copy name insto sun_path, prefixed by null to indicate abstract namespace */
+ snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s",
+ svr->name);
+ socket_unix.sun_path[0] = '\0';
+ socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix,
+ svr->name);
+#else
+ WRN("Your system does not support abstract sockets!");
+ return 0;
+#endif
+ }
+ else
+ {
+ strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
+ socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
+ }
+
+ if (connect(svr->fd, (struct sockaddr *)&socket_unix,
+ socket_unix_len) < 0)
+ {
+ ERR("local connection failed: %s", strerror(errno));
+ return 0;
+ }
+
+ svr->path = strdup(buf);
+ if (!svr->path)
+ return 0;
+
+ if (svr->type & ECORE_CON_SSL)
+ ecore_con_ssl_server_init(svr);
+
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ cb_done, svr, NULL, NULL);
+ if (!svr->fd_handler)
+ return 0;
+
+ if (!svr->delete_me) ecore_con_event_server_add(svr);
+
+ return 1;
+#endif
+}
+
+int
+ecore_con_local_listen(
+ Ecore_Con_Server *svr,
+ Eina_Bool (*
+ cb_listen)(void *data,
+ Ecore_Fd_Handler *
+ fd_handler),
+ void *data
+ EINA_UNUSED)
+{
+#ifdef HAVE_LOCAL_SOCKETS
+ char buf[4096];
+ struct sockaddr_un socket_unix;
+ struct linger lin;
+ mode_t pmode;
+ const char *homedir;
+ struct stat st;
+ mode_t mask;
+ int socket_unix_len;
+
+ mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
+ {
+ homedir = getenv("HOME");
+ if (!homedir)
+ homedir = getenv("TMP");
+
+ if (!homedir)
+ homedir = "/tmp";
+
+ mask = S_IRUSR | S_IWUSR | S_IXUSR;
+ snprintf(buf, sizeof(buf), "%s/.ecore", homedir);
+ if (stat(buf, &st) < 0)
+ mkdir(buf, mask);
+
+ snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name);
+ if (stat(buf, &st) < 0)
+ mkdir(buf, mask);
+
+ snprintf(buf,
+ sizeof(buf),
+ "%s/.ecore/%s/%i",
+ homedir,
+ svr->name,
+ svr->port);
+ mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
+ }
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
+ {
+ mask = 0;
+ if (svr->name[0] == '/')
+ {
+ if (svr->port >= 0)
+ snprintf(buf,
+ sizeof(buf),
+ "%s|%i",
+ svr->name,
+ svr->port);
+ else
+ snprintf(buf,
+ sizeof(buf),
+ "%s",
+ svr->name);
+ }
+ else
+ snprintf(buf,
+ sizeof(buf),
+ "/tmp/.ecore_service|%s|%i",
+ svr->name,
+ svr->port);
+ }
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ strncpy(buf, svr->name,
+ sizeof(buf));
+
+ pmode = umask(mask);
+start:
+ svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (svr->fd < 0)
+ goto error_umask;
+
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
+ goto error_umask;
+
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
+ goto error_umask;
+
+ lin.l_onoff = 1;
+ lin.l_linger = 0;
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
+ sizeof(struct linger)) < 0)
+ goto error_umask;
+
+ socket_unix.sun_family = AF_UNIX;
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ {
+#ifdef HAVE_ABSTRACT_SOCKETS
+ /* . is a placeholder */
+ snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s",
+ svr->name);
+ /* first char null indicates abstract namespace */
+ socket_unix.sun_path[0] = '\0';
+ socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix,
+ svr->name);
+#else
+ ERR("Your system does not support abstract sockets!");
+ goto error_umask;
+#endif
+ }
+ else
+ {
+ strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
+ socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
+ }
+
+ if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
+ {
+ if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) ||
+ ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)) &&
+ (connect(svr->fd, (struct sockaddr *)&socket_unix,
+ socket_unix_len) < 0) &&
+ (unlink(buf) >= 0))
+ goto start;
+ else
+ goto error_umask;
+ }
+
+ if (listen(svr->fd, 4096) < 0)
+ goto error_umask;
+
+ svr->path = strdup(buf);
+ if (!svr->path)
+ goto error_umask;
+
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ cb_listen, svr, NULL, NULL);
+ umask(pmode);
+ if (!svr->fd_handler)
+ goto error;
+
+ return 1;
+
+error_umask:
+ umask(pmode);
+error:
+#endif /* HAVE_LOCAL_SOCKETS */
+ return 0;
+}
+
diff --git a/src/lib/ecore_con/ecore_con_local_win32.c b/src/lib/ecore_con/ecore_con_local_win32.c
new file mode 100644
index 0000000000..2b7e5c5bd2
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_local_win32.c
@@ -0,0 +1,754 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <process.h>
+
+#include <Evil.h>
+#include <Ecore.h>
+
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+#define BUFSIZE 512
+
+
+static int _ecore_con_local_init_count = 0;
+
+int
+ecore_con_local_init(void)
+{
+ if (++_ecore_con_local_init_count != 1)
+ return _ecore_con_local_init_count;
+
+ return _ecore_con_local_init_count;
+}
+
+int
+ecore_con_local_shutdown(void)
+{
+ if (--_ecore_con_local_init_count != 0)
+ return _ecore_con_local_init_count;
+
+ return _ecore_con_local_init_count;
+}
+
+
+static Eina_Bool
+_ecore_con_local_win32_server_read_client_handler(void *data, Ecore_Win32_Handler *wh)
+{
+ Ecore_Con_Client *cl;
+ void *buf;
+ DWORD n;
+ Eina_Bool broken_pipe = EINA_FALSE;
+
+ cl = (Ecore_Con_Client *)data;
+
+ if (!ResetEvent(cl->host_server->event_read))
+ return ECORE_CALLBACK_RENEW;
+
+ buf = malloc(cl->host_server->nbr_bytes);
+ if (!buf)
+ return ECORE_CALLBACK_RENEW;
+
+ if (ReadFile(cl->host_server->pipe, buf, cl->host_server->nbr_bytes, &n, NULL))
+ {
+ if (!cl->delete_me)
+ ecore_con_event_client_data(cl, buf, cl->host_server->nbr_bytes, EINA_FALSE);
+ cl->host_server->want_write = 1;
+ }
+ else
+ {
+ if (GetLastError() == ERROR_BROKEN_PIPE)
+ broken_pipe = EINA_TRUE;
+ }
+
+ if (broken_pipe)
+ {
+#if 0
+ char *msg;
+
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_client_error(cl, msg);
+ free(msg);
+ }
+#endif
+ _ecore_con_client_kill(cl);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (cl->host_server->want_write)
+ ecore_con_local_win32_client_flush(cl);
+
+ ecore_main_win32_handler_del(wh);
+
+ return ECORE_CALLBACK_DONE;
+}
+
+static Eina_Bool
+_ecore_con_local_win32_server_peek_client_handler(void *data, Ecore_Win32_Handler *wh)
+{
+ Ecore_Con_Client *cl;
+#if 0
+ char *msg;
+#endif
+
+ cl = (Ecore_Con_Client *)data;
+
+ if (!ResetEvent(cl->host_server->event_peek))
+ return ECORE_CALLBACK_RENEW;
+
+#if 0
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_server_error(cl->host_server, msg);
+ free(msg);
+ }
+#endif
+ _ecore_con_server_kill(cl->host_server);
+ return ECORE_CALLBACK_CANCEL;
+
+ ecore_main_win32_handler_del(wh);
+
+ return ECORE_CALLBACK_DONE;
+}
+
+static Eina_Bool
+_ecore_con_local_win32_client_peek_server_handler(void *data, Ecore_Win32_Handler *wh)
+{
+ Ecore_Con_Server *svr;
+#if 0
+ char *msg;
+#endif
+
+ svr = (Ecore_Con_Server *)data;
+
+ if (!ResetEvent(svr->event_peek))
+ return ECORE_CALLBACK_RENEW;
+#if 0
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_server_error(svr, msg);
+ free(msg);
+ }
+#endif
+ _ecore_con_server_kill(svr);
+ return ECORE_CALLBACK_CANCEL;
+
+ ecore_main_win32_handler_del(wh);
+
+ return ECORE_CALLBACK_DONE;
+}
+
+static Eina_Bool
+_ecore_con_local_win32_client_read_server_handler(void *data, Ecore_Win32_Handler *wh)
+{
+ Ecore_Con_Server *svr;
+ void *buf;
+ DWORD n;
+ Eina_Bool broken_pipe = EINA_FALSE;
+
+ svr = (Ecore_Con_Server *)data;
+
+ if (!ResetEvent(svr->event_read))
+ return ECORE_CALLBACK_RENEW;
+
+ buf = malloc(svr->nbr_bytes);
+ if (!buf)
+ return ECORE_CALLBACK_RENEW;
+
+ if (ReadFile(svr->pipe, buf, svr->nbr_bytes, &n, NULL))
+ {
+ if (!svr->delete_me)
+ ecore_con_event_server_data(svr, buf, svr->nbr_bytes, EINA_FALSE);
+ svr->want_write = 1;
+ }
+ else
+ {
+ if (GetLastError() == ERROR_BROKEN_PIPE)
+ broken_pipe = EINA_TRUE;
+ }
+
+ if (broken_pipe)
+ {
+#if 0
+ char *msg;
+
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_server_error(svr, msg);
+ free(msg);
+ }
+#endif
+ _ecore_con_server_kill(svr);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (svr->want_write)
+ ecore_con_local_win32_server_flush(svr);
+
+ ecore_main_win32_handler_del(wh);
+
+ return ECORE_CALLBACK_DONE;
+}
+
+/* thread to read data sent by the server to the client */
+static unsigned int __stdcall
+_ecore_con_local_win32_client_read_server_thread(void *data)
+{
+ Ecore_Con_Server *svr;
+ DWORD nbr_bytes = 0;
+
+ svr = (Ecore_Con_Server *)data;
+
+ svr->read_stopped = EINA_FALSE;
+
+ while (!svr->read_stop)
+ {
+ if (PeekNamedPipe(svr->pipe, NULL, 0, NULL, &nbr_bytes, NULL))
+ {
+ if (nbr_bytes <= 0)
+ continue;
+
+ svr->nbr_bytes = nbr_bytes;
+ if (!SetEvent(svr->event_read))
+ continue;
+ }
+ else
+ {
+ if (GetLastError() == ERROR_BROKEN_PIPE)
+ {
+ if (!SetEvent(svr->event_peek))
+ continue;
+ break;
+ }
+ }
+ }
+
+ printf(" ### %s\n", __FUNCTION__);
+ svr->read_stopped = EINA_TRUE;
+ _endthreadex(0);
+ return 0;
+}
+
+/* thread to read data sent by the client to the server */
+static unsigned int __stdcall
+_ecore_con_local_win32_server_read_client_thread(void *data)
+{
+ Ecore_Con_Client *cl;
+ DWORD nbr_bytes = 0;
+
+ cl = (Ecore_Con_Client *)data;
+
+ cl->host_server->read_stopped = EINA_FALSE;
+
+ while (!cl->host_server->read_stop)
+ {
+ if (PeekNamedPipe(cl->host_server->pipe, NULL, 0, NULL, &nbr_bytes, NULL))
+ {
+ if (nbr_bytes <= 0)
+ continue;
+
+ cl->host_server->nbr_bytes = nbr_bytes;
+ if (!SetEvent(cl->host_server->event_read))
+ continue;
+ }
+ else
+ {
+ if (GetLastError() == ERROR_BROKEN_PIPE)
+ {
+ if (!SetEvent(cl->host_server->event_peek))
+ continue;
+ break;
+ }
+ }
+ }
+
+ printf(" ### %s\n", __FUNCTION__);
+ cl->host_server->read_stopped = EINA_TRUE;
+ _endthreadex(0);
+ return 0;
+}
+
+static Eina_Bool
+_ecore_con_local_win32_client_add(void *data, Ecore_Win32_Handler *wh)
+{
+ Ecore_Con_Client *cl = NULL;
+ Ecore_Con_Server *svr;
+ Ecore_Win32_Handler *handler_read;
+ Ecore_Win32_Handler *handler_peek;
+
+ svr = (Ecore_Con_Server *)data;
+
+ if (!svr->pipe)
+ return ECORE_CALLBACK_CANCEL;
+
+ if (svr->delete_me)
+ return ECORE_CALLBACK_CANCEL;
+
+ if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) &&
+ (svr->client_count >= (unsigned int)svr->client_limit))
+ return ECORE_CALLBACK_CANCEL;
+
+ cl = calloc(1, sizeof(Ecore_Con_Client));
+ if (!cl)
+ {
+ ERR("allocation failed");
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ cl->host_server = svr;
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+
+ cl->host_server->event_read = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!cl->host_server->event_read)
+ {
+ ERR("Can not create event read");
+ goto free_cl;
+ }
+
+ handler_read = ecore_main_win32_handler_add(cl->host_server->event_read,
+ _ecore_con_local_win32_server_read_client_handler,
+ cl);
+ if (!handler_read)
+ {
+ ERR("Can not create handler read");
+ goto close_event_read;
+ }
+
+ cl->host_server->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!cl->host_server->event_peek)
+ {
+ ERR("Can not create event peek");
+ goto del_handler_read;
+ }
+
+ handler_peek = ecore_main_win32_handler_add(cl->host_server->event_peek,
+ _ecore_con_local_win32_server_peek_client_handler,
+ cl);
+ if (!handler_peek)
+ {
+ ERR("Can not create handler peek");
+ goto close_event_peek;
+ }
+
+ cl->host_server->read_stopped = EINA_TRUE;
+ cl->host_server->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_server_read_client_thread, cl, CREATE_SUSPENDED, NULL);
+ if (!cl->host_server->thread_read)
+ {
+ ERR("Can not launch thread");
+ goto del_handler_peek;
+ }
+
+ svr->clients = eina_list_append(svr->clients, cl);
+ svr->client_count++;
+
+ if (!cl->delete_me)
+ ecore_con_event_client_add(cl);
+
+ ecore_main_win32_handler_del(wh);
+
+ ResumeThread(cl->host_server->thread_read);
+ return ECORE_CALLBACK_DONE;
+
+ del_handler_peek:
+ ecore_main_win32_handler_del(handler_peek);
+ close_event_peek:
+ CloseHandle(cl->host_server->event_peek);
+ del_handler_read:
+ ecore_main_win32_handler_del(handler_read);
+ close_event_read:
+ CloseHandle(cl->host_server->event_read);
+ free_cl:
+ free(cl);
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static unsigned int __stdcall
+_ecore_con_local_win32_listening(void *data)
+{
+ Ecore_Con_Server *svr;
+ BOOL res;
+
+ svr = (Ecore_Con_Server *)data;
+
+ while (1)
+ {
+ res = ConnectNamedPipe(svr->pipe, NULL);
+ if (!res)
+ {
+ ERR("Opening the connection to the client failed");
+ CloseHandle(svr->pipe);
+ svr->pipe = NULL;
+ }
+ break;
+ }
+
+ DBG("Client connected");
+
+ printf(" ### %s\n", __FUNCTION__);
+ _endthreadex(0);
+ return 0;
+}
+
+Eina_Bool
+ecore_con_local_listen(Ecore_Con_Server *svr)
+{
+ char buf[256];
+ HANDLE thread_listening;
+ Ecore_Win32_Handler *handler;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ {
+ ERR("Your system does not support abstract sockets!");
+ return EINA_FALSE;
+ }
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
+ snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name);
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
+ {
+ const char *computername;
+
+ computername = getenv("CoMPUTERNAME");
+ snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name);
+ }
+
+ svr->path = strdup(buf);
+ if (!svr->path)
+ {
+ ERR("Allocation failed");
+ return EINA_FALSE;
+ }
+
+ /*
+ * synchronuous
+ * block mode
+ * wait mode
+ */
+ svr->pipe = CreateNamedPipe(svr->path,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ BUFSIZE,
+ BUFSIZE,
+ 5000,
+ NULL);
+ if (svr->pipe == INVALID_HANDLE_VALUE)
+ {
+ ERR("Creation of the named pipe failed");
+ goto free_path;
+ }
+
+ /*
+ * We use ConnectNamedPipe() to wait for a client to connect.
+ * As the function is blocking, to let the main loop continuing
+ * its iterations, we call ConnectNamedPipe() in a thread
+ */
+ thread_listening = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_listening, svr, CREATE_SUSPENDED, NULL);
+ if (!thread_listening)
+ {
+ ERR("Creation of the listening thread failed");
+ goto close_pipe;
+ }
+
+ handler = ecore_main_win32_handler_add(thread_listening,
+ _ecore_con_local_win32_client_add,
+ svr);
+ if (!handler)
+ {
+ ERR("Creation of the client add handler failed");
+ goto del_handler;
+ }
+
+ svr->read_stopped = EINA_TRUE;
+ ResumeThread(thread_listening);
+
+ return EINA_TRUE;
+
+ del_handler:
+ ecore_main_win32_handler_del(handler);
+ close_pipe:
+ CloseHandle(svr->pipe);
+ free_path:
+ free(svr->path);
+ svr->path = NULL;
+
+ return EINA_FALSE;
+}
+
+void
+ecore_con_local_win32_server_del(Ecore_Con_Server *svr)
+{
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ return;
+
+ if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
+ ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
+ return;
+
+ svr->read_stop = 1;
+ while (!svr->read_stopped)
+ Sleep(100);
+
+ if (svr->event_peek)
+ CloseHandle(svr->event_peek);
+ svr->event_peek = NULL;
+ if (svr->event_read)
+ CloseHandle(svr->event_read);
+ svr->event_read = NULL;
+ free(svr->path);
+ svr->path = NULL;
+ if (svr->pipe)
+ CloseHandle(svr->pipe);
+ svr->pipe = NULL;
+}
+
+void
+ecore_con_local_win32_client_del(Ecore_Con_Client *cl)
+{
+ if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ return;
+
+ if (((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
+ ((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
+ return;
+
+ cl->host_server->read_stop = 1;
+ while (!cl->host_server->read_stopped)
+ Sleep(100);
+
+ if (cl->host_server->event_peek)
+ CloseHandle(cl->host_server->event_peek);
+ cl->host_server->event_peek = NULL;
+ if (cl->host_server->event_read)
+ CloseHandle(cl->host_server->event_read);
+ cl->host_server->event_read = NULL;
+ free(cl->host_server->path);
+ cl->host_server->path = NULL;
+ if (cl->host_server->pipe)
+ CloseHandle(cl->host_server->pipe);
+ cl->host_server->pipe = NULL;
+}
+
+Eina_Bool
+ecore_con_local_connect(Ecore_Con_Server *svr,
+ Eina_Bool (*cb_done)(void *data,
+ Ecore_Fd_Handler *fd_handler))
+{
+ char buf[256];
+ Ecore_Win32_Handler *handler_read;
+ Ecore_Win32_Handler *handler_peek;
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ {
+ ERR("Your system does not support abstract sockets!");
+ return EINA_FALSE;
+ }
+
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
+ snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name);
+ else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
+ {
+ const char *computername;
+
+ computername = getenv("COMPUTERNAME");
+ snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name);
+ }
+
+ while (1)
+ {
+ svr->pipe = CreateFile(buf,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (svr->pipe != INVALID_HANDLE_VALUE)
+ break;
+
+ /* if pipe not busy, we exit */
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ ERR("Connection to a server failed");
+ return EINA_FALSE;
+ }
+
+ /* pipe busy, so we wait for it */
+ if (!WaitNamedPipe(buf, NMPWAIT_WAIT_FOREVER))
+ {
+ ERR("Can not wait for a server");
+ goto close_pipe;
+ }
+ }
+
+ svr->path = strdup(buf);
+ if (!svr->path)
+ {
+ ERR("Allocation failed");
+ goto close_pipe;
+ }
+
+ svr->event_read = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!svr->event_read)
+ {
+ ERR("Can not create event read");
+ goto free_path;
+ }
+
+ handler_read = ecore_main_win32_handler_add(svr->event_read,
+ _ecore_con_local_win32_client_read_server_handler,
+ svr);
+ if (!handler_read)
+ {
+ ERR("Can not create handler read");
+ goto close_event_read;
+ }
+
+ svr->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!svr->event_peek)
+ {
+ ERR("Can not create event peek");
+ goto del_handler_read;
+ }
+
+ handler_peek = ecore_main_win32_handler_add(svr->event_peek,
+ _ecore_con_local_win32_client_peek_server_handler,
+ svr);
+ if (!handler_peek)
+ {
+ ERR("Can not create handler peek");
+ goto close_event_peek;
+ }
+
+ svr->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_client_read_server_thread, svr, CREATE_SUSPENDED, NULL);
+ if (!svr->thread_read)
+ {
+ ERR("Can not launch thread");
+ goto del_handler_peek;
+ }
+
+ if (!svr->delete_me) ecore_con_event_server_add(svr);
+
+ ResumeThread(svr->thread_read);
+
+ return EINA_TRUE;
+
+ del_handler_peek:
+ ecore_main_win32_handler_del(handler_peek);
+ close_event_peek:
+ CloseHandle(svr->event_peek);
+ del_handler_read:
+ ecore_main_win32_handler_del(handler_read);
+ close_event_read:
+ CloseHandle(svr->event_read);
+ free_path:
+ free(svr->path);
+ svr->path = NULL;
+ close_pipe:
+ CloseHandle(svr->pipe);
+
+ return EINA_FALSE;
+}
+
+Eina_Bool
+ecore_con_local_win32_server_flush(Ecore_Con_Server *svr)
+{
+ int num;
+ BOOL res;
+ DWORD written;
+
+ /* This check should never be true */
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
+ return EINA_TRUE;
+
+ if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
+ ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
+ return EINA_FALSE;
+
+ num = eina_binbuf_length_get(svr->buf) - svr->write_buf_offset;
+ if (num <= 0) return EINA_TRUE;
+
+ res = WriteFile(svr->pipe, eina_binbuf_string_get(svr->buf) + svr->write_buf_offset, num, &written, NULL);
+ if (!res)
+ {
+ char *msg;
+
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_server_error(svr, msg);
+ free(msg);
+ }
+ _ecore_con_server_kill(svr);
+ }
+
+ svr->write_buf_offset += written;
+ if (svr->write_buf_offset >= eina_binbuf_length_get(svr->buf))
+ {
+ svr->write_buf_offset = 0;
+ eina_binbuf_free(svr->buf);
+ svr->buf = NULL;
+ svr->want_write = 0;
+ }
+ else if (written < (DWORD)num)
+ svr->want_write = 1;
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+ecore_con_local_win32_client_flush(Ecore_Con_Client *cl)
+{
+ Ecore_Con_Type type;
+ int num;
+ BOOL res;
+ DWORD written;
+
+ type = cl->host_server->type & ECORE_CON_TYPE;
+
+ /* This check should never be true */
+ if (type == ECORE_CON_LOCAL_ABSTRACT)
+ return EINA_TRUE;
+
+ if ((type != ECORE_CON_LOCAL_USER) &&
+ (type != ECORE_CON_LOCAL_SYSTEM))
+ return EINA_FALSE;
+
+ num = eina_binbuf_length_get(cl->buf) - cl->buf_offset;
+ if (num <= 0) return EINA_TRUE;
+
+ res = WriteFile(cl->host_server->pipe, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num, &written, NULL);
+ if (!res)
+ {
+ char *msg;
+
+ msg = evil_last_error_get();
+ if (msg)
+ {
+ ecore_con_event_client_error(cl, msg);
+ free(msg);
+ }
+ _ecore_con_client_kill(cl);
+ }
+
+ cl->buf_offset += written;
+ if (cl->buf_offset >= eina_binbuf_length_get(cl->buf))
+ {
+ cl->buf_offset = 0;
+ eina_binbuf_free(cl->buf);
+ cl->buf = NULL;
+ cl->host_server->want_write = 0;
+ }
+ else if (written < (DWORD)num)
+ cl->host_server->want_write = 1;
+
+ return EINA_TRUE;
+}
diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h
new file mode 100644
index 0000000000..d8b0abb5c3
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_private.h
@@ -0,0 +1,390 @@
+#ifndef _ECORE_CON_PRIVATE_H
+#define _ECORE_CON_PRIVATE_H
+
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+
+#define ECORE_MAGIC_CON_SERVER 0x77665544
+#define ECORE_MAGIC_CON_CLIENT 0x77556677
+#define ECORE_MAGIC_CON_URL 0x77074255
+
+#define ECORE_CON_TYPE 0x0f
+#define ECORE_CON_SSL 0xf0
+#define ECORE_CON_SUPER_SSL 0xf00
+
+#if USE_GNUTLS
+# include <gnutls/gnutls.h>
+#elif USE_OPENSSL
+# include <openssl/ssl.h>
+#endif
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
+
+#define READBUFSIZ 65536
+
+extern int _ecore_con_log_dom;
+
+#ifdef ECORE_CON_DEFAULT_LOG_COLOR
+#undef ECORE_LOG_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_CON_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_con_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_con_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_con_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_con_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_con_log_dom, __VA_ARGS__)
+
+typedef struct _Ecore_Con_Lookup Ecore_Con_Lookup;
+typedef struct _Ecore_Con_Info Ecore_Con_Info;
+typedef struct Ecore_Con_Socks Ecore_Con_Socks_v4;
+typedef struct Ecore_Con_Socks_v5 Ecore_Con_Socks_v5;
+typedef void (*Ecore_Con_Info_Cb)(void *data, Ecore_Con_Info *infos);
+
+typedef enum _Ecore_Con_State
+{
+ ECORE_CON_CONNECTED,
+ ECORE_CON_DISCONNECTED,
+ ECORE_CON_INPROGRESS
+} Ecore_Con_State;
+
+typedef enum _Ecore_Con_Ssl_Error
+{
+ ECORE_CON_SSL_ERROR_NONE = 0,
+ ECORE_CON_SSL_ERROR_NOT_SUPPORTED,
+ ECORE_CON_SSL_ERROR_INIT_FAILED,
+ ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED,
+ ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED
+} Ecore_Con_Ssl_Error;
+
+typedef enum _Ecore_Con_Ssl_Handshake
+{
+ ECORE_CON_SSL_STATE_DONE = 0,
+ ECORE_CON_SSL_STATE_HANDSHAKING,
+ ECORE_CON_SSL_STATE_INIT
+} Ecore_Con_Ssl_State;
+
+typedef enum Ecore_Con_Proxy_State
+{ /* named PROXY instead of SOCKS in case some handsome and enterprising
+ * developer decides to add HTTP CONNECT support
+ */
+ ECORE_CON_PROXY_STATE_DONE = 0,
+ ECORE_CON_PROXY_STATE_RESOLVED,
+ ECORE_CON_PROXY_STATE_INIT,
+ ECORE_CON_PROXY_STATE_READ,
+ ECORE_CON_PROXY_STATE_AUTH,
+ ECORE_CON_PROXY_STATE_REQUEST,
+ ECORE_CON_PROXY_STATE_CONFIRM,
+} Ecore_Con_Proxy_State;
+
+struct _Ecore_Con_Client
+{
+ ECORE_MAGIC;
+ int fd;
+ Ecore_Con_Server *host_server;
+ void *data;
+ Ecore_Fd_Handler *fd_handler;
+ unsigned int buf_offset;
+ Eina_Binbuf *buf;
+ const char *ip;
+ Eina_List *event_count;
+ struct sockaddr *client_addr;
+ int client_addr_len;
+ double start_time;
+ Ecore_Timer *until_deletion;
+ double disconnect_time;
+#if USE_GNUTLS
+ gnutls_datum_t session_ticket;
+ gnutls_session_t session;
+#elif USE_OPENSSL
+ SSL *ssl;
+ int ssl_err;
+#endif
+ Ecore_Con_Ssl_State ssl_state;
+ Eina_Bool handshaking : 1;
+ Eina_Bool upgrade : 1; /* STARTTLS queued */
+ Eina_Bool delete_me : 1; /* del event has been queued */
+};
+
+struct _Ecore_Con_Server
+{
+ ECORE_MAGIC;
+ int fd;
+ Ecore_Con_Type type;
+ char *name;
+ int port;
+ char *path;
+ void *data;
+ Ecore_Fd_Handler *fd_handler;
+ Eina_List *clients;
+ unsigned int client_count;
+ Eina_Binbuf *buf;
+ unsigned int write_buf_offset;
+ Eina_List *infos;
+ Eina_List *event_count;
+ int client_limit;
+ pid_t ppid;
+ /* socks */
+ Ecore_Con_Socks *ecs;
+ Ecore_Con_Proxy_State ecs_state;
+ int ecs_addrlen;
+ unsigned char ecs_addr[16];
+ unsigned int ecs_buf_offset;
+ Eina_Binbuf *ecs_buf;
+ Eina_Binbuf *ecs_recvbuf;
+ const char *proxyip;
+ int proxyport;
+ /* endsocks */
+ const char *verify_name;
+#if USE_GNUTLS
+ gnutls_session_t session;
+ gnutls_anon_client_credentials_t anoncred_c;
+ gnutls_anon_server_credentials_t anoncred_s;
+ gnutls_psk_client_credentials_t pskcred_c;
+ gnutls_psk_server_credentials_t pskcred_s;
+ gnutls_certificate_credentials_t cert;
+ char *cert_file;
+ gnutls_dh_params_t dh_params;
+#elif USE_OPENSSL
+ SSL_CTX *ssl_ctx;
+ SSL *ssl;
+ int ssl_err;
+#endif
+ double start_time;
+ Ecore_Timer *until_deletion;
+ double disconnect_time;
+ double client_disconnect_time;
+ const char *ip;
+ Eina_Bool created : 1; /* @c EINA_TRUE if server is our listening server */
+ Eina_Bool connecting : 1; /* @c EINA_FALSE if just initialized or connected */
+ Eina_Bool handshaking : 1; /* @c EINA_TRUE if server is ssl handshaking */
+ Eina_Bool upgrade : 1; /* STARTTLS queued */
+ Eina_Bool disable_proxy : 1; /* proxy should never be used with this connection */
+ Eina_Bool ssl_prepared : 1;
+ Eina_Bool use_cert : 1; /* @c EINA_TRUE if using certificate auth */
+ Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */
+ Eina_Bool verify : 1; /* @c EINA_TRUE if certificates will be verified */
+ Eina_Bool verify_basic : 1; /* @c EINA_TRUE if certificates will be verified only against the hostname */
+ Eina_Bool reject_excess_clients : 1;
+ Eina_Bool delete_me : 1; /* del event has been queued */
+#ifdef _WIN32
+ Eina_Bool want_write : 1;
+ Eina_Bool read_stop : 1;
+ Eina_Bool read_stopped : 1;
+ HANDLE pipe;
+ HANDLE thread_read;
+ HANDLE event_read;
+ HANDLE event_peek;
+ DWORD nbr_bytes;
+#endif
+};
+
+#ifdef HAVE_CURL
+struct _Ecore_Con_Url
+{
+ ECORE_MAGIC;
+ CURL *curl_easy;
+ struct curl_slist *headers;
+ Eina_List *additional_headers;
+ Eina_List *response_headers;
+ const char *url;
+ long proxy_type;
+ int status;
+
+ Ecore_Timer *timer;
+
+ Ecore_Con_Url_Time time_condition;
+ double timestamp;
+ void *data;
+
+ void *post_data;
+
+ int received;
+ int write_fd;
+
+ unsigned int event_count;
+ Eina_Bool dead : 1;
+ Eina_Bool multi : 1;
+};
+#endif
+
+struct _Ecore_Con_Info
+{
+ unsigned int size;
+ struct addrinfo info;
+ char ip[NI_MAXHOST];
+ char service[NI_MAXSERV];
+};
+
+struct _Ecore_Con_Lookup
+{
+ Ecore_Con_Dns_Cb done_cb;
+ const void *data;
+};
+
+struct Ecore_Con_Socks /* v4 */
+{
+ unsigned char version;
+
+ const char *ip;
+ int port;
+ const char *username;
+ unsigned int ulen;
+ Eina_Bool lookup : 1;
+ Eina_Bool bind : 1;
+};
+
+struct Ecore_Con_Socks_v5
+{
+ unsigned char version;
+
+ const char *ip;
+ int port;
+ const char *username;
+ unsigned int ulen;
+ Eina_Bool lookup : 1;
+ Eina_Bool bind : 1;
+ /* v5 only */
+ unsigned char method;
+ const char *password;
+ unsigned int plen;
+};
+
+extern Ecore_Con_Socks *_ecore_con_proxy_once;
+extern Ecore_Con_Socks *_ecore_con_proxy_global;
+void ecore_con_socks_init(void);
+void ecore_con_socks_shutdown(void);
+Eina_Bool ecore_con_socks_svr_init(Ecore_Con_Server *svr);
+void ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num);
+void ecore_con_socks_dns_cb(const char *canonname, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr);
+/* from ecore_con.c */
+void ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info);
+void ecore_con_event_proxy_bind(Ecore_Con_Server *svr);
+void ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate);
+void ecore_con_event_server_del(Ecore_Con_Server *svr);
+#define ecore_con_event_server_error(svr, error) _ecore_con_event_server_error((svr), (char*)(error), EINA_TRUE)
+void _ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate);
+void ecore_con_event_client_add(Ecore_Con_Client *cl);
+void ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate);
+void ecore_con_event_client_del(Ecore_Con_Client *cl);
+void ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error);
+void _ecore_con_server_kill(Ecore_Con_Server *svr);
+void _ecore_con_client_kill(Ecore_Con_Client *cl);
+/* from ecore_local_win32.c */
+#ifdef _WIN32
+Eina_Bool ecore_con_local_listen(Ecore_Con_Server *svr);
+Eina_Bool ecore_con_local_connect(Ecore_Con_Server *svr,
+ Eina_Bool (*cb_done)(void *data,
+ Ecore_Fd_Handler *fd_handler));
+Eina_Bool ecore_con_local_win32_server_flush(Ecore_Con_Server *svr);
+Eina_Bool ecore_con_local_win32_client_flush(Ecore_Con_Client *cl);
+void ecore_con_local_win32_server_del(Ecore_Con_Server *svr);
+void ecore_con_local_win32_client_del(Ecore_Con_Client *cl);
+#else
+/* from ecore_local.c */
+int ecore_con_local_init(void);
+int ecore_con_local_shutdown(void);
+int ecore_con_local_connect(Ecore_Con_Server *svr,
+ Eina_Bool (*cb_done)(
+ void *data,
+ Ecore_Fd_Handler *fd_handler),
+ void *data);
+int ecore_con_local_listen(Ecore_Con_Server *svr,
+ Eina_Bool (*cb_listen)(
+ void *data,
+ Ecore_Fd_Handler *fd_handler),
+ void *data);
+#endif
+
+/* from ecore_con_info.c */
+int ecore_con_info_init(void);
+int ecore_con_info_shutdown(void);
+int ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data);
+int ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data);
+int ecore_con_info_udp_connect(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data);
+int ecore_con_info_udp_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data);
+int ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data);
+void ecore_con_info_data_clear(void *info);
+
+void ecore_con_event_server_add(Ecore_Con_Server *svr);
+
+
+/* from ecore_con_ssl.c */
+Ecore_Con_Ssl_Error ecore_con_ssl_init(void);
+Ecore_Con_Ssl_Error ecore_con_ssl_shutdown(void);
+Ecore_Con_Ssl_Error ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, int ssl_type);
+Ecore_Con_Ssl_Error ecore_con_ssl_server_init(Ecore_Con_Server *svr);
+Ecore_Con_Ssl_Error ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr);
+int ecore_con_ssl_server_read(Ecore_Con_Server *svr,
+ unsigned char *buf,
+ int size);
+int ecore_con_ssl_server_write(Ecore_Con_Server *svr,
+ const unsigned char *buf,
+ int size);
+Ecore_Con_Ssl_Error ecore_con_ssl_client_init(Ecore_Con_Client *svr);
+Ecore_Con_Ssl_Error ecore_con_ssl_client_shutdown(Ecore_Con_Client *svr);
+int ecore_con_ssl_client_read(Ecore_Con_Client *svr,
+ unsigned char *buf,
+ int size);
+int ecore_con_ssl_client_write(Ecore_Con_Client *svr,
+ const unsigned char *buf,
+ int size);
+
+int ecore_con_info_get(Ecore_Con_Server *svr,
+ Ecore_Con_Info_Cb done_cb,
+ void *data,
+ struct addrinfo *hints);
+
+
+#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \
+ TYPE *Type##_alloc(void); \
+ void Type##_free(TYPE *e);
+
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Add, ecore_con_event_client_add);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Del, ecore_con_event_client_del);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Write, ecore_con_event_client_write);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Data, ecore_con_event_client_data);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Error, ecore_con_event_server_error);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Error, ecore_con_event_client_error);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Add, ecore_con_event_server_add);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Del, ecore_con_event_server_del);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Write, ecore_con_event_server_write);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Data, ecore_con_event_server_data);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind);
+
+void ecore_con_mempool_init(void);
+void ecore_con_mempool_shutdown(void);
+
+#undef GENERIC_ALLOC_FREE_HEADER
+
+#endif
diff --git a/src/lib/ecore_con/ecore_con_socks.c b/src/lib/ecore_con/ecore_con_socks.c
new file mode 100644
index 0000000000..a6df8a9640
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_socks.c
@@ -0,0 +1,962 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+
+/* if net/if.h is not found or if an older versions of net/if.h is provided
+ which does not define IF_NAMESIZE. We must define it ourselves */
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+/* http://tools.ietf.org/html/rfc1928
+ o X'00' NO AUTHENTICATION REQUIRED
+ o X'01' GSSAPI
+ o X'02' USERNAME/PASSWORD
+ o X'03' to X'7F' IANA ASSIGNED
+ o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
+ o X'FF' NO ACCEPTABLE METHODS
+*/
+#define ECORE_CON_SOCKS_V5_METHOD_NONE 0
+#define ECORE_CON_SOCKS_V5_METHOD_GSSAPI 1
+#define ECORE_CON_SOCKS_V5_METHOD_USERPASS 2
+
+static int ECORE_CON_SOCKS_V5_METHODS[] =
+{
+ ECORE_CON_SOCKS_V5_METHOD_NONE,
+// ECORE_CON_SOCKS_V5_METHOD_GSSAPI, TODO
+ ECORE_CON_SOCKS_V5_METHOD_USERPASS
+};
+
+#define ECORE_CON_SOCKS_V5_TOTAL_METHODS sizeof(ECORE_CON_SOCKS_V5_METHODS)
+
+#define _ecore_con_server_kill(svr) do { \
+ DBG("KILL %p", (svr)); \
+ _ecore_con_server_kill((svr)); \
+} while (0)
+
+#define ECORE_CON_SOCKS_VERSION_CHECK(X) do { \
+ if (!(X) || ((X)->version < 4) || ((X)->version > 5)) \
+ return; \
+} while (0)
+#define ECORE_CON_SOCKS_VERSION_CHECK_RETURN(X, ret) do { \
+ if (!(X) || ((X)->version < 4) || ((X)->version > 5)) \
+ return (ret); \
+} while (0)
+
+#define ECORE_CON_SOCKS_CAST(X) \
+ Ecore_Con_Socks_v4 *v4 = NULL; \
+ Ecore_Con_Socks_v5 *v5 = NULL; \
+ if ((X) && ((X)->version == 4)) \
+ v4 = (Ecore_Con_Socks_v4 *)(X); \
+ else if ((X) && ((X)->version == 5)) \
+ v5 = (Ecore_Con_Socks_v5 *)(X);
+
+Eina_List *ecore_con_socks_proxies = NULL;
+
+static Ecore_Con_Socks *
+_ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username, size_t ulen, const char *password, size_t plen)
+{
+ Eina_List *l;
+ Ecore_Con_Socks_v5 *ecs;
+
+ if (!ecore_con_socks_proxies) return NULL;
+
+ EINA_LIST_FOREACH(ecore_con_socks_proxies, l, ecs)
+ {
+ if (ecs->version != version) continue;
+ if (strcmp(ecs->ip, ip)) continue;
+ if ((port != -1) && (port != ecs->port)) continue;
+ if (ulen != ecs->ulen) continue;
+ if (username && strcmp(ecs->username, username)) continue;
+ if (version == 5)
+ {
+ if (plen != ecs->plen) continue;
+ if (password && strcmp(ecs->password, password)) continue;
+ }
+ return (Ecore_Con_Socks*)ecs;
+ }
+ return NULL;
+}
+
+static void
+_ecore_con_socks_free(Ecore_Con_Socks *ecs)
+{
+ ECORE_CON_SOCKS_VERSION_CHECK(ecs);
+
+ if (_ecore_con_proxy_once == ecs) _ecore_con_proxy_once = NULL;
+ if (_ecore_con_proxy_global == ecs) _ecore_con_proxy_global = NULL;
+ eina_stringshare_del(ecs->ip);
+ eina_stringshare_del(ecs->username);
+ free(ecs);
+}
+
+static Eina_Bool
+_ecore_con_socks_svr_init_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4)
+{
+ size_t addrlen, buflen, ulen = 1;
+ unsigned char *sbuf;
+
+ addrlen = v4->lookup ? strlen(svr->name) + 1 : 0;
+ if (v4->username) ulen += v4->ulen;
+ buflen = sizeof(char) * (8 + ulen + addrlen);
+ sbuf = malloc(buflen);
+ if (!sbuf)
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure!");
+ _ecore_con_server_kill(svr);
+ return EINA_FALSE;
+ }
+ /* http://en.wikipedia.org/wiki/SOCKS */
+ sbuf[0] = 4;
+ sbuf[1] = v4->bind ? 2 : 1;
+ sbuf[2] = svr->port >> 8;
+ sbuf[3] = svr->port & 0xff;
+ if (addrlen)
+ {
+ sbuf[4] = sbuf[5] = sbuf[6] = 0;
+ sbuf[7] = 1;
+ }
+ else
+ /* SOCKSv4 only handles IPV4, so addrlen is always 4 */
+ memcpy(sbuf + 4, svr->ecs_addr, 4);
+ if (v4->username)
+ memcpy(sbuf + 8, v4->username, ulen);
+ else
+ sbuf[8] = 0;
+ if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen);
+
+ svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_con_socks_svr_init_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5)
+{
+ size_t buflen;
+ unsigned int x;
+ unsigned char *sbuf;
+
+ if (v5->username)
+ buflen = sizeof(char) * (2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS);
+ else
+ buflen = 3;
+ sbuf = malloc(buflen);
+ if (!sbuf)
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure!");
+ _ecore_con_server_kill(svr);
+ return EINA_FALSE;
+ }
+ /* http://en.wikipedia.org/wiki/SOCKS
+ * http://tools.ietf.org/html/rfc1928
+ */
+ sbuf[0] = 5;
+ if (v5->username)
+ {
+ sbuf[1] = ECORE_CON_SOCKS_V5_TOTAL_METHODS;
+ for (x = 2; x < 2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS; x++)
+ sbuf[x] = ECORE_CON_SOCKS_V5_METHODS[x - 2];
+ }
+ else
+ {
+ sbuf[1] = 1;
+ sbuf[2] = ECORE_CON_SOCKS_V5_METHOD_NONE;
+ }
+
+ svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen);
+ return EINA_TRUE;
+}
+
+#define ECORE_CON_SOCKS_READ(EXACT) \
+ if (num < EXACT) \
+ { \
+ if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new(); \
+ if (!svr->ecs_recvbuf) goto error; \
+ eina_binbuf_append_length(svr->ecs_recvbuf, buf, num); \
+ /* the slowest connection on earth */ \
+ if (eina_binbuf_length_get(svr->ecs_recvbuf) != EXACT) return; \
+ data = eina_binbuf_string_get(svr->ecs_recvbuf); \
+ } \
+ else if (num > EXACT) goto error; \
+ else \
+ data = buf
+
+static void
+_ecore_con_socks_read_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4 EINA_UNUSED, const unsigned char *buf, unsigned int num)
+{
+ const unsigned char *data;
+ DBG("SOCKS: %d bytes", num);
+ ECORE_CON_SOCKS_READ(8);
+
+/* http://ufasoft.com/doc/socks4_protocol.htm */
+ if (data[0]) goto error;
+ switch (data[1])
+ {
+ case 90:
+ /* success! */
+ break;
+ case 91:
+ ecore_con_event_server_error(svr, "proxy request rejected or failed");
+ goto error;
+ case 92:
+ ecore_con_event_server_error(svr, "proxying SOCKS server could not perform authentication");
+ goto error;
+ case 93:
+ ecore_con_event_server_error(svr, "proxy request authentication rejected");
+ goto error;
+ default:
+ ecore_con_event_server_error(svr, "garbage data from proxy");
+ goto error;
+ }
+ if (svr->ecs->bind)
+ {
+ unsigned int nport;
+ char naddr[IF_NAMESIZE];
+
+ memcpy(&nport, &data[2], 2);
+ svr->proxyport = ntohl(nport);
+
+ if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error;
+ svr->proxyip = eina_stringshare_add(naddr);
+ ecore_con_event_proxy_bind(svr);
+ }
+ svr->ecs_state = ECORE_CON_PROXY_STATE_DONE;
+ INF("PROXY CONNECTED");
+ if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
+ svr->ecs_recvbuf = NULL;
+ svr->ecs_buf_offset = svr->ecs_addrlen = 0;
+ memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr));
+ if (!svr->ssl_state)
+ ecore_con_event_server_add(svr);
+ if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf)))
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
+ return;
+error:
+ _ecore_con_server_kill(svr);
+}
+
+static Eina_Bool
+_ecore_con_socks_auth_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5)
+{
+ size_t size;
+ unsigned char *data;
+ switch (v5->method)
+ {
+ case ECORE_CON_SOCKS_V5_METHOD_NONE:
+ svr->ecs_state = ECORE_CON_PROXY_STATE_REQUEST;
+ return EINA_TRUE;
+ case ECORE_CON_SOCKS_V5_METHOD_GSSAPI:
+ return EINA_TRUE;
+ case ECORE_CON_SOCKS_V5_METHOD_USERPASS:
+ if (!v5->username) return EINA_FALSE;
+ if (!v5->password) v5->plen = 1;
+ /* http://tools.ietf.org/html/rfc1929 */
+ size = sizeof(char) * (3 + v5->ulen + v5->plen);
+ data = malloc(size);
+ if (!data) break;
+ data[0] = 1;
+ data[1] = v5->ulen;
+ memcpy(&data[2], v5->username, v5->ulen);
+ data[1 + v5->ulen] = v5->plen;
+ if (v5->password)
+ memcpy(&data[2 + v5->ulen], v5->password, v5->plen);
+ else
+ data[2 + v5->ulen] = 0;
+ svr->ecs_buf = eina_binbuf_manage_new_length(data, size);
+ return EINA_TRUE;
+ default:
+ break;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_ecore_con_socks_read_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5, const unsigned char *buf, unsigned int num)
+{
+ const unsigned char *data;
+
+ DBG("SOCKS: %d bytes", num);
+ switch (svr->ecs_state)
+ {
+
+ case ECORE_CON_PROXY_STATE_READ:
+ ECORE_CON_SOCKS_READ(2);
+ /* http://en.wikipedia.org/wiki/SOCKS */
+ if (data[0] != 5) goto error;
+ if (data[1] == 0xFF)
+ {
+ ecore_con_event_server_error(svr, "proxy authentication methods rejected");
+ goto error;
+ }
+ v5->method = data[1];
+ if (!_ecore_con_socks_auth_v5(svr, v5)) goto error;
+ if (svr->ecs_state == ECORE_CON_PROXY_STATE_REQUEST)
+ {
+ /* run again to skip auth reading */
+ _ecore_con_socks_read_v5(svr, v5, NULL, 0);
+ return;
+ }
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ svr->ecs_state = ECORE_CON_PROXY_STATE_AUTH;
+ break;
+ case ECORE_CON_PROXY_STATE_AUTH:
+ ECORE_CON_SOCKS_READ(2);
+ switch (v5->method)
+ {
+ case ECORE_CON_SOCKS_V5_METHOD_NONE:
+ CRIT("HOW DID THIS HAPPEN?????????");
+ goto error;
+ case ECORE_CON_SOCKS_V5_METHOD_GSSAPI:
+ /* TODO: this */
+ break;
+ case ECORE_CON_SOCKS_V5_METHOD_USERPASS:
+ if (data[0] != 1)
+ {
+ ecore_con_event_server_error(svr, "protocol error");
+ goto error; /* wrong version */
+ }
+ if (data[1])
+ {
+ ecore_con_event_server_error(svr, "proxy request authentication rejected");
+ goto error;
+ }
+ default:
+ break;
+ }
+ case ECORE_CON_PROXY_STATE_REQUEST:
+ {
+ size_t addrlen, buflen;
+ unsigned char *sbuf;
+ addrlen = v5->lookup ? strlen(svr->name) + 1 : (unsigned int)svr->ecs_addrlen;
+ buflen = sizeof(char) * (6 + addrlen);
+ sbuf = malloc(buflen);
+ if (!sbuf)
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure!");
+ goto error;
+ }
+ sbuf[0] = 5;
+ sbuf[1] = v5->bind ? 2 : 1; /* TODO: 0x03 for UDP port association */
+ sbuf[2] = 0;
+ if (v5->lookup) /* domain name */
+ {
+ sbuf[3] = 3;
+ sbuf[4] = addrlen - 1;
+ memcpy(sbuf + 5, svr->name, addrlen - 1);
+ }
+ else
+ {
+ sbuf[3] = (svr->ecs_addrlen == 4) ? 1 : 4;
+ memcpy(sbuf + 4, svr->ecs_addr, addrlen);
+ }
+ sbuf[addrlen + 4] = svr->port >> 8;
+ sbuf[addrlen + 5] = svr->port & 0xff;
+
+ svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen);
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ break;
+ }
+ case ECORE_CON_PROXY_STATE_CONFIRM:
+ {
+ /* this is ugly because we have to read an exact number of bytes,
+ * but we don't know what that number is until we've already read
+ * at least 5 bytes to determine the length of the unknown stream.
+ * yep.
+ */
+ size_t to_read, len = svr->ecs_recvbuf ? eina_binbuf_length_get(svr->ecs_recvbuf) : 0;
+ if (num + len < 5)
+ {
+ /* guarantees we get called again */
+ ECORE_CON_SOCKS_READ(5);
+ }
+ if (len >= 5)
+ {
+ data = eina_binbuf_string_get(svr->ecs_recvbuf);
+ data += 3;
+ }
+ else
+ data = buf + 3 - len;
+ switch (data[0])
+ {
+ case 1:
+ to_read = 4;
+ break;
+ case 3:
+ to_read = data[1] + 1;
+ break;
+ case 4:
+ to_read = 16;
+ /* lazy debugging stub comment */
+ break;
+ default:
+ ecore_con_event_server_error(svr, "protocol error");
+ goto error;
+ }
+ /* at this point, we finally know exactly how much we need to read */
+ ECORE_CON_SOCKS_READ(6 + to_read);
+
+ if (data[0] != 5)
+ {
+ ecore_con_event_server_error(svr, "protocol error");
+ goto error; /* wrong version */
+ }
+ switch (data[1])
+ {
+ case 0:
+ break;
+ case 1:
+ ecore_con_event_server_error(svr, "general proxy failure");
+ goto error;
+ case 2:
+ ecore_con_event_server_error(svr, "connection not allowed by ruleset");
+ goto error;
+ case 3:
+ ecore_con_event_server_error(svr, "network unreachable");
+ goto error;
+ case 4:
+ ecore_con_event_server_error(svr, "host unreachable");
+ goto error;
+ case 5:
+ ecore_con_event_server_error(svr, "connection refused by destination host");
+ goto error;
+ case 6:
+ ecore_con_event_server_error(svr, "TTL expired");
+ goto error;
+ case 7:
+ ecore_con_event_server_error(svr, "command not supported / protocol error");
+ goto error;
+ case 8:
+ ecore_con_event_server_error(svr, "address type not supported");
+ default:
+ goto error;
+ }
+ if (data[2])
+ {
+ ecore_con_event_server_error(svr, "protocol error");
+ goto error;
+ }
+ memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr));
+ if (!svr->ssl_state)
+ ecore_con_event_server_add(svr);
+ if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf)))
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
+ svr->ecs_buf_offset = svr->ecs_addrlen = 0;
+ svr->ecs_state = ECORE_CON_PROXY_STATE_DONE;
+ INF("PROXY CONNECTED");
+ break;
+ }
+ default:
+ break;
+ }
+ if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
+ svr->ecs_recvbuf = NULL;
+
+ return;
+error:
+ _ecore_con_server_kill(svr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+void
+ecore_con_socks_shutdown(void)
+{
+ Ecore_Con_Socks *ecs;
+ EINA_LIST_FREE(ecore_con_socks_proxies, ecs)
+ _ecore_con_socks_free(ecs);
+ _ecore_con_proxy_once = NULL;
+ _ecore_con_proxy_global = NULL;
+}
+
+void
+ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num)
+{
+ ECORE_CON_SOCKS_VERSION_CHECK(svr->ecs);
+ ECORE_CON_SOCKS_CAST(svr->ecs);
+
+ if (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) return;
+
+ if (v4) _ecore_con_socks_read_v4(svr, v4, buf, (unsigned int)num);
+ else _ecore_con_socks_read_v5(svr, v5, buf, (unsigned int)num);
+}
+
+Eina_Bool
+ecore_con_socks_svr_init(Ecore_Con_Server *svr)
+{
+ ECORE_CON_SOCKS_VERSION_CHECK_RETURN(svr->ecs, EINA_FALSE);
+ ECORE_CON_SOCKS_CAST(svr->ecs);
+
+ if (!svr->ip) return EINA_FALSE;
+ if (svr->ecs_buf) return EINA_FALSE;
+ if (svr->ecs_state != ECORE_CON_PROXY_STATE_INIT) return EINA_FALSE;
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ if (v4) return _ecore_con_socks_svr_init_v4(svr, v4);
+ return _ecore_con_socks_svr_init_v5(svr, v5);
+}
+
+void
+ecore_con_socks_dns_cb(const char *canonname EINA_UNUSED, const char *ip, struct sockaddr *addr, int addrlen EINA_UNUSED, Ecore_Con_Server *svr)
+{
+ svr->ip = eina_stringshare_add(ip);
+ svr->ecs_state++;
+ if (addr->sa_family == AF_INET)
+ {
+ memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4);
+ svr->ecs_addrlen = 4;
+ }
+#ifdef HAVE_IPV6
+ else
+ {
+ memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, 16);
+ svr->ecs_addrlen = 16;
+ }
+#endif
+ ecore_con_socks_svr_init(svr);
+}
+
+void
+ecore_con_socks_init(void)
+{
+ const char *socks;
+ char *h, *p, *l, *u = NULL;
+ char buf[512];
+ int port, lookup = 0;
+ Eina_Bool v5 = EINA_FALSE;
+ Ecore_Con_Socks *ecs;
+ unsigned char addr[sizeof(struct in_addr)];
+#ifdef HAVE_IPV6
+ unsigned char addr6[sizeof(struct in6_addr)];
+#endif
+
+ /* ECORE_CON_SOCKS_V4=[user@]host-port:[1|0] */
+ socks = getenv("ECORE_CON_SOCKS_V4");
+ if (!socks)
+ {
+ /* ECORE_CON_SOCKS_V5=[user@]host-port:[1|0] */
+ socks = getenv("ECORE_CON_SOCKS_V5");
+ v5 = EINA_TRUE;
+ }
+ if ((!socks) || (!socks[0]) || (strlen(socks) > 512)) return;
+ strncpy(buf, socks, sizeof(buf));
+ h = strchr(buf, '@');
+ /* username */
+ if (h && (h - buf > 0)) *h++ = 0, u = buf;
+ else h = buf;
+
+ /* host ip; I ain't resolvin shit here */
+ p = strchr(h, '-');
+ if (!p) return;
+ *p++ = 0;
+ if (!inet_pton(AF_INET, h, addr))
+#ifdef HAVE_IPV6
+ {
+ if (!v5) return;
+ if (!inet_pton(AF_INET6, h, addr6))
+ return;
+ }
+#else
+ return;
+#endif
+
+ errno = 0;
+ port = strtol(p, &l, 10);
+ if (errno || (port < 0) || (port > 65535)) return;
+ if (l && (l[0] == ':'))
+ lookup = (l[1] == '1');
+ if (v5)
+ ecs = ecore_con_socks5_remote_add(h, port, u, NULL);
+ else
+ ecs = ecore_con_socks4_remote_add(h, port, u);
+ if (!ecs) return;
+ ecore_con_socks_lookup_set(ecs, lookup);
+ ecore_con_socks_apply_always(ecs);
+ INF("Added global proxy server %s%s%s:%d - DNS lookup %s",
+ u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @defgroup Ecore_Con_Socks_Group Ecore Connection SOCKS functions
+ * @{
+ */
+
+/**
+ * Add a SOCKS v4 proxy to the proxy list
+ *
+ * Use this to create (or return, if previously added) a SOCKS proxy
+ * object which can be used by any ecore_con servers.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy
+ * @param username The username to use for the proxy (OPTIONAL)
+ * @return An allocated proxy object, or NULL on failure
+ * @note This object NEVER needs to be explicitly freed.
+ * @since 1.2
+ */
+EAPI Ecore_Con_Socks *
+ecore_con_socks4_remote_add(const char *ip, int port, const char *username)
+{
+ Ecore_Con_Socks *ecs;
+ size_t ulen = 0;
+
+ if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
+
+ if (username)
+ {
+ ulen = strlen(username);
+ /* max length for protocol */
+ if ((!ulen) || (ulen > 255)) return NULL;
+ }
+ ecs = _ecore_con_socks_find(4, ip, port, username, ulen, NULL, 0);
+ if (ecs) return ecs;
+
+ ecs = calloc(1, sizeof(Ecore_Con_Socks_v4));
+ if (!ecs) return NULL;
+
+ ecs->version = 4;
+ ecs->ip = eina_stringshare_add(ip);
+ ecs->port = port;
+ ecs->username = eina_stringshare_add(username);
+ ecs->ulen = ulen;
+ ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs);
+ return ecs;
+}
+
+/**
+ * Find a SOCKS v4 proxy in the proxy list
+ *
+ * Use this to determine if a SOCKS proxy was previously added by checking
+ * the proxy list against the parameters given.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @return true only if a proxy exists matching the given params
+ * @note This function matches slightly more loosely than ecore_con_socks4_remote_add(), and
+ * ecore_con_socks4_remote_add() should be used to return the actual object.
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks4_remote_exists(const char *ip, int port, const char *username)
+{
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])))
+ return EINA_FALSE;
+ return !!_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0);
+}
+
+/**
+ * Remove a SOCKS v4 proxy from the proxy list and delete it
+ *
+ * Use this to remove a SOCKS proxy from the proxy list by checking
+ * the list against the parameters given. The proxy will then be deleted.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @note This function matches in the same way as ecore_con_socks4_remote_exists().
+ * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks4_remote_del(const char *ip, int port, const char *username)
+{
+ Ecore_Con_Socks_v4 *v4;
+
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return;
+ if (!ecore_con_socks_proxies) return;
+
+ v4 = (Ecore_Con_Socks_v4*)_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0);
+ if (!v4) return;
+ ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4);
+ _ecore_con_socks_free((Ecore_Con_Socks*)v4);
+}
+/**
+ * Add a SOCKS v5 proxy to the proxy list
+ *
+ * Use this to create (or return, if previously added) a SOCKS proxy
+ * object which can be used by any ecore_con servers.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy
+ * @param username The username to use for the proxy (OPTIONAL)
+ * @param password The password to use for the proxy (OPTIONAL)
+ * @return An allocated proxy object, or NULL on failure
+ * @note This object NEVER needs to be explicitly freed.
+ * @since 1.2
+ */
+EAPI Ecore_Con_Socks *
+ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password)
+{
+ Ecore_Con_Socks_v5 *ecs5;
+ size_t ulen = 0, plen = 0;
+
+ if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
+
+ if (username)
+ {
+ ulen = strlen(username);
+ /* max length for protocol */
+ if ((!ulen) || (ulen > 255)) return NULL;
+ }
+ if (password)
+ {
+ plen = strlen(password);
+ /* max length for protocol */
+ if ((!plen) || (plen > 255)) return NULL;
+ }
+ ecs5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, ulen, password, plen);
+ if (ecs5) return (Ecore_Con_Socks*)ecs5;
+
+ ecs5 = calloc(1, sizeof(Ecore_Con_Socks_v5));
+ if (!ecs5) return NULL;
+
+ ecs5->version = 5;
+ ecs5->ip = eina_stringshare_add(ip);
+ ecs5->port = port;
+ ecs5->username = eina_stringshare_add(username);
+ ecs5->ulen = ulen;
+ ecs5->password = eina_stringshare_add(password);
+ ecs5->plen = plen;
+ ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs5);
+ return (Ecore_Con_Socks*)ecs5;
+}
+
+/**
+ * Find a SOCKS v5 proxy in the proxy list
+ *
+ * Use this to determine if a SOCKS proxy was previously added by checking
+ * the proxy list against the parameters given.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @param password The password used for the proxy (OPTIONAL)
+ * @return true only if a proxy exists matching the given params
+ * @note This function matches slightly more loosely than ecore_con_socks5_remote_add(), and
+ * ecore_con_socks5_remote_add() should be used to return the actual object.
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password)
+{
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
+ return EINA_FALSE;
+ return !!_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
+}
+
+/**
+ * Remove a SOCKS v5 proxy from the proxy list and delete it
+ *
+ * Use this to remove a SOCKS proxy from the proxy list by checking
+ * the list against the parameters given. The proxy will then be deleted.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @param password The password used for the proxy (OPTIONAL)
+ * @note This function matches in the same way as ecore_con_socks4_remote_exists().
+ * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password)
+{
+ Ecore_Con_Socks_v5 *v5;
+
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0])))
+ return;
+ if (!ecore_con_socks_proxies) return;
+
+ v5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0);
+ if (!v5) return;
+ ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v5);
+ _ecore_con_socks_free((Ecore_Con_Socks*)v5);
+}
+
+/**
+ * Set DNS lookup mode on an existing SOCKS proxy
+ *
+ * According to RFC, SOCKS v4 does not require that a proxy perform
+ * its own DNS lookups for addresses. SOCKS v4a specifies the protocol
+ * for this. SOCKS v5 allows DNS lookups.
+ * If you want to enable remote DNS lookup and are sure that your
+ * proxy supports it, use this function.
+ * @param ecs The proxy object
+ * @param enable If true, the proxy will perform the dns lookup
+ * @note By default, this setting is DISABLED.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable)
+{
+ ECORE_CON_SOCKS_VERSION_CHECK(ecs);
+ ecs->lookup = !!enable;
+}
+
+/**
+ * Get DNS lookup mode on an existing SOCKS proxy
+ *
+ * According to RFC, SOCKS v4 does not require that a proxy perform
+ * its own DNS lookups for addresses. SOCKS v4a specifies the protocol
+ * for this. SOCKS v5 allows DNS lookups.
+ * This function returns whether lookups are enabled on a proxy object.
+ * @param ecs The proxy object
+ * @return If true, the proxy will perform the dns lookup
+ * @note By default, this setting is DISABLED.
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs)
+{
+ ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, EINA_FALSE);
+ return ecs->lookup;
+}
+
+/**
+ * Enable bind mode on a SOCKS proxy
+ *
+ * Use this function to enable binding a remote port for use with a remote server.
+ * For more information, see http://ufasoft.com/doc/socks4_protocol.htm
+ * @param ecs The proxy object
+ * @param is_bind If true, the connection established will be a port binding
+ * @warning Be aware that changing the operation mode of an active proxy may result in undefined behavior
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ecs);
+ ECORE_CON_SOCKS_VERSION_CHECK(ecs);
+ ecs->bind = !!is_bind;
+}
+
+/**
+ * Return bind mode of a SOCKS proxy
+ *
+ * Use this function to return bind mode of a proxy (binding a remote port for use with a remote server).
+ * For more information, see http://ufasoft.com/doc/socks4_protocol.htm
+ * @param ecs The proxy object
+ * @return If true, the connection established will be a port binding
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks_bind_get(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, EINA_FALSE);
+ ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, EINA_FALSE);
+ return ecs->bind;
+}
+
+/**
+ * Return SOCKS version of a SOCKS proxy
+ *
+ * Use this function to return the SOCKS protocol version of a proxy
+ * @param ecs The proxy object
+ * @return 0 on error, else 4/5
+ * @since 1.2
+ */
+EAPI unsigned int
+ecore_con_socks_version_get(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, 0);
+ ECORE_CON_SOCKS_VERSION_CHECK_RETURN(ecs, 0);
+ return ecs->version;
+}
+
+/**
+ * Remove a SOCKS v4 proxy from the proxy list and delete it
+ *
+ * Use this to remove a SOCKS proxy from the proxy list by directly deleting the object given.
+ * @param ecs The proxy object to delete
+ * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_remote_del(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ecs);
+ if (!ecore_con_socks_proxies) return;
+
+ ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, ecs);
+ _ecore_con_socks_free(ecs);
+}
+
+/**
+ * Set a proxy object to be used with the next server created with ecore_con_server_connect()
+ *
+ * This function sets a proxy for the next ecore_con connection. After the next server is created,
+ * the proxy will NEVER be applied again unless explicitly enabled.
+ * @param ecs The proxy object
+ * @see ecore_con_socks_apply_always()
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_apply_once(Ecore_Con_Socks *ecs)
+{
+ _ecore_con_proxy_once = ecs;
+}
+
+/**
+ * Set a proxy object to be used with all servers created with ecore_con_server_connect()
+ *
+ * This function sets a proxy for all ecore_con connections. It will always be used.
+ * @param ecs The proxy object
+ * @see ecore_con_socks_apply_once()
+ * @since 1.2
+ * @note ecore-con supports setting this through environment variables like so:
+ * ECORE_CON_SOCKS_V4=[user@]server-port:lookup
+ * ECORE_CON_SOCKS_V5=[user@]server-port:lookup
+ * user is the OPTIONAL string that would be passed to the proxy as the username
+ * server is the IP_ADDRESS of the proxy server
+ * port is the port to connect to on the proxy server
+ * lookup is 1 if the proxy should perform all DNS lookups, otherwise 0 or omitted
+ */
+EAPI void
+ecore_con_socks_apply_always(Ecore_Con_Socks *ecs)
+{
+ _ecore_con_proxy_global = ecs;
+}
+/** @} */
diff --git a/src/lib/ecore_con/ecore_con_ssl.c b/src/lib/ecore_con/ecore_con_ssl.c
new file mode 100644
index 0000000000..609d29161a
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_ssl.c
@@ -0,0 +1,2141 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#if USE_GNUTLS
+# include <gnutls/gnutls.h>
+# include <gnutls/x509.h>
+# include <gcrypt.h>
+#elif USE_OPENSSL
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/dh.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#include <sys/stat.h>
+#include "Ecore.h"
+#include "ecore_con_private.h"
+
+EAPI int ECORE_CON_EVENT_CLIENT_UPGRADE = 0;
+EAPI int ECORE_CON_EVENT_SERVER_UPGRADE = 0;
+
+static int _init_con_ssl_init_count = 0;
+
+#ifdef USE_GNUTLS
+# ifdef EINA_HAVE_THREADS
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+# endif
+
+static int _client_connected = 0;
+
+# define SSL_SUFFIX(ssl_func) ssl_func ## _gnutls
+# define _ECORE_CON_SSL_AVAILABLE 1
+
+#elif USE_OPENSSL
+
+# define SSL_SUFFIX(ssl_func) ssl_func ## _openssl
+# define _ECORE_CON_SSL_AVAILABLE 2
+
+#else
+# define SSL_SUFFIX(ssl_func) ssl_func ## _none
+# define _ECORE_CON_SSL_AVAILABLE 0
+
+#endif
+
+#if USE_GNUTLS
+static void
+_gnutls_print_errors(void *conn, int type, int ret)
+{
+ char buf[1024];
+
+ if (!ret) return;
+
+ snprintf(buf, sizeof(buf), "GNUTLS error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
+ if (type == ECORE_CON_EVENT_CLIENT_ERROR)
+ ecore_con_event_client_error(conn, buf);
+ else
+ ecore_con_event_server_error(conn, buf);
+}
+
+static void
+_gnutls_print_session(const gnutls_datum_t *cert_list, unsigned int cert_list_size)
+{
+ char *c = NULL;
+ gnutls_x509_crt_t crt;
+ unsigned int x;
+
+ if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return;
+ for (x = 0; x < cert_list_size; x++)
+ {
+ gnutls_x509_crt_init(&crt);
+ gnutls_x509_crt_import(crt, &cert_list[x], GNUTLS_X509_FMT_DER);
+ gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_FULL, (gnutls_datum_t*)&c);
+ INF("CERTIFICATE:\n%s", c);
+ gnutls_free(c);
+ gnutls_x509_crt_deinit(crt);
+ crt = NULL;
+ }
+}
+
+#ifdef ISCOMFITOR
+static void
+_gnutls_log_func(int level,
+ const char *str)
+{
+ char buf[128];
+ strncat(buf, str, strlen(str) - 1);
+ DBG("|<%d>| %s", level, buf);
+}
+#endif
+
+static const char *
+SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
+{
+ switch (status)
+ {
+ case GNUTLS_HANDSHAKE_HELLO_REQUEST:
+ return "Hello request";
+
+ case GNUTLS_HANDSHAKE_CLIENT_HELLO:
+ return "Client hello";
+
+ case GNUTLS_HANDSHAKE_SERVER_HELLO:
+ return "Server hello";
+
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
+ return "New session ticket";
+
+ case GNUTLS_HANDSHAKE_CERTIFICATE_PKT:
+ return "Certificate packet";
+
+ case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE:
+ return "Server key exchange";
+
+ case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
+ return "Certificate request";
+
+ case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
+ return "Server hello done";
+
+ case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
+ return "Certificate verify";
+
+ case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
+ return "Client key exchange";
+
+ case GNUTLS_HANDSHAKE_FINISHED:
+ return "Finished";
+
+ case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
+ return "Supplemental";
+ }
+ return NULL;
+}
+
+#elif USE_OPENSSL
+
+static void
+_openssl_print_verify_error(int error)
+{
+ switch (error)
+ {
+#define ERROR(X) \
+ case (X): \
+ ERR("%s", #X); \
+ break
+#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
+ ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_GET_CRL
+ ERROR(X509_V_ERR_UNABLE_TO_GET_CRL);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
+ ERROR(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+#endif
+#ifdef X509_V_ERR_CERT_SIGNATURE_FAILURE
+ ERROR(X509_V_ERR_CERT_SIGNATURE_FAILURE);
+#endif
+#ifdef X509_V_ERR_CRL_SIGNATURE_FAILURE
+ ERROR(X509_V_ERR_CRL_SIGNATURE_FAILURE);
+#endif
+#ifdef X509_V_ERR_CERT_NOT_YET_VALID
+ ERROR(X509_V_ERR_CERT_NOT_YET_VALID);
+#endif
+#ifdef X509_V_ERR_CERT_HAS_EXPIRED
+ ERROR(X509_V_ERR_CERT_HAS_EXPIRED);
+#endif
+#ifdef X509_V_ERR_CRL_NOT_YET_VALID
+ ERROR(X509_V_ERR_CRL_NOT_YET_VALID);
+#endif
+#ifdef X509_V_ERR_CRL_HAS_EXPIRED
+ ERROR(X509_V_ERR_CRL_HAS_EXPIRED);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+#endif
+#ifdef X509_V_ERR_OUT_OF_MEM
+ ERROR(X509_V_ERR_OUT_OF_MEM);
+#endif
+#ifdef X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
+ ERROR(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
+#endif
+#ifdef X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
+ ERROR(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+ ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_CERT_CHAIN_TOO_LONG
+ ERROR(X509_V_ERR_CERT_CHAIN_TOO_LONG);
+#endif
+#ifdef X509_V_ERR_CERT_REVOKED
+ ERROR(X509_V_ERR_CERT_REVOKED);
+#endif
+#ifdef X509_V_ERR_INVALID_CA
+ ERROR(X509_V_ERR_INVALID_CA);
+#endif
+#ifdef X509_V_ERR_PATH_LENGTH_EXCEEDED
+ ERROR(X509_V_ERR_PATH_LENGTH_EXCEEDED);
+#endif
+#ifdef X509_V_ERR_INVALID_PURPOSE
+ ERROR(X509_V_ERR_INVALID_PURPOSE);
+#endif
+#ifdef X509_V_ERR_CERT_UNTRUSTED
+ ERROR(X509_V_ERR_CERT_UNTRUSTED);
+#endif
+#ifdef X509_V_ERR_CERT_REJECTED
+ ERROR(X509_V_ERR_CERT_REJECTED);
+#endif
+ /* These are 'informational' when looking for issuer cert */
+#ifdef X509_V_ERR_SUBJECT_ISSUER_MISMATCH
+ ERROR(X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
+#endif
+#ifdef X509_V_ERR_AKID_SKID_MISMATCH
+ ERROR(X509_V_ERR_AKID_SKID_MISMATCH);
+#endif
+#ifdef X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
+ ERROR(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_CERTSIGN
+ ERROR(X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
+#endif
+
+#ifdef X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
+ ERROR(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
+#endif
+#ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION
+ ERROR(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN
+ ERROR(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
+#endif
+#ifdef X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION
+ ERROR(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
+#endif
+#ifdef X509_V_ERR_INVALID_NON_CA
+ ERROR(X509_V_ERR_INVALID_NON_CA);
+#endif
+#ifdef X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED
+ ERROR(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE
+ ERROR(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED
+ ERROR(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
+#endif
+
+#ifdef X509_V_ERR_INVALID_EXTENSION
+ ERROR(X509_V_ERR_INVALID_EXTENSION);
+#endif
+#ifdef X509_V_ERR_INVALID_POLICY_EXTENSION
+ ERROR(X509_V_ERR_INVALID_POLICY_EXTENSION);
+#endif
+#ifdef X509_V_ERR_NO_EXPLICIT_POLICY
+ ERROR(X509_V_ERR_NO_EXPLICIT_POLICY);
+#endif
+#ifdef X509_V_ERR_DIFFERENT_CRL_SCOPE
+ ERROR(X509_V_ERR_DIFFERENT_CRL_SCOPE);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE
+ ERROR(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
+#endif
+
+#ifdef X509_V_ERR_UNNESTED_RESOURCE
+ ERROR(X509_V_ERR_UNNESTED_RESOURCE);
+#endif
+
+#ifdef X509_V_ERR_PERMITTED_VIOLATION
+ ERROR(X509_V_ERR_PERMITTED_VIOLATION);
+#endif
+#ifdef X509_V_ERR_EXCLUDED_VIOLATION
+ ERROR(X509_V_ERR_EXCLUDED_VIOLATION);
+#endif
+#ifdef X509_V_ERR_SUBTREE_MINMAX
+ ERROR(X509_V_ERR_SUBTREE_MINMAX);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE
+ ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX
+ ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
+ ERROR(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
+#endif
+#ifdef X509_V_ERR_CRL_PATH_VALIDATION_ERROR
+ ERROR(X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
+#endif
+
+ /* The application is not happy */
+#ifdef X509_V_ERR_APPLICATION_VERIFICATION
+ ERROR(X509_V_ERR_APPLICATION_VERIFICATION);
+#endif
+ }
+#undef ERROR
+}
+
+static void
+_openssl_print_errors(void *conn, int type)
+{
+ char buf[1024];
+ do
+ {
+ unsigned long err;
+
+ err = ERR_get_error();
+ if (!err) break;
+ snprintf(buf, sizeof(buf), "OpenSSL error: %s", ERR_reason_error_string(err));
+ if (type == ECORE_CON_EVENT_CLIENT_ERROR)
+ ecore_con_event_client_error(conn, buf);
+ else
+ ecore_con_event_server_error(conn, buf);
+
+ } while (1);
+}
+
+static Eina_Bool
+_openssl_name_verify(const char *name, const char *svrname)
+{
+ if (name[0] == '*')
+ {
+ /* we allow *.domain.TLD with a wildcard, but nothing else */
+ const char *p, *s;
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((name[1] != '.') || (!name[2]), EINA_FALSE);
+ p = strchr(name + 1, '*');
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!!p, EINA_FALSE);
+ /* verify that we have a domain of at least *.X.TLD and not *.TLD */
+ p = strchr(name + 2, '.');
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!p, EINA_FALSE);
+ s = strchr(svrname, '.');
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!s, EINA_FALSE);
+ /* same as above for the stored name */
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!strchr(s + 1, '.'), EINA_FALSE);
+ if (strcasecmp(s, name + 1))
+ {
+ ERR("%s != %s", s, name + 1);
+ return EINA_FALSE;
+ }
+ }
+ else
+ if (strcasecmp(name, svrname))
+ {
+ ERR("%s != %s", name, svrname);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
+static void
+_openssl_print_session(SSL *ssl)
+{
+ /* print session info into DBG */
+ SSL_SESSION *s;
+ STACK_OF(X509) *sk;
+ BIO *b;
+ char log[4096], *p;
+ int x;
+
+ if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return;
+
+ memset(log, 0, sizeof(log));
+ b = BIO_new(BIO_s_mem());
+ sk = SSL_get_peer_cert_chain(ssl);
+ if (sk)
+ {
+ DBG("CERTIFICATES:");
+ for (x = 0; x < sk_X509_num(sk); x++)
+ {
+ p = X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, x)), log, sizeof(log));
+ DBG("%2d s:%s", x, p);
+ p = X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, x)), log, sizeof(log));
+ DBG(" i:%s", p);
+ PEM_write_X509(stderr, sk_X509_value(sk, x));
+ }
+ }
+ s = SSL_get_session(ssl);
+ SSL_SESSION_print(b, s);
+ fprintf(stderr, "\n");
+ while (BIO_read(b, log, sizeof(log)) > 0)
+ fprintf(stderr, "%s", log);
+
+ BIO_free(b);
+}
+
+#endif
+
+#define SSL_ERROR_CHECK_GOTO_ERROR(X) \
+ do \
+ { \
+ if ((X)) \
+ { \
+ ERR("Error at %s:%s:%d!", __FILE__, __PRETTY_FUNCTION__, __LINE__); \
+ goto error; \
+ } \
+ } \
+ while (0)
+
+static Ecore_Con_Ssl_Error
+ SSL_SUFFIX(_ecore_con_ssl_init) (void);
+static Ecore_Con_Ssl_Error
+ SSL_SUFFIX(_ecore_con_ssl_shutdown) (void);
+
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (Ecore_Con_Server * svr, const char *ca_file);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (Ecore_Con_Server * svr, const char *crl_file);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (Ecore_Con_Server * svr, const char *cert);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (Ecore_Con_Server * svr, const char *key_file);
+
+static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_prepare) (Ecore_Con_Server * svr, int ssl_type);
+static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_init) (Ecore_Con_Server * svr);
+static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (Ecore_Con_Server *svr);
+static int SSL_SUFFIX(_ecore_con_ssl_server_read) (Ecore_Con_Server *svr, unsigned char *buf, int size);
+static int SSL_SUFFIX(_ecore_con_ssl_server_write) (Ecore_Con_Server *svr, const unsigned char *buf, int size);
+
+static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_init) (Ecore_Con_Client * cl);
+static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (Ecore_Con_Client *cl);
+static int SSL_SUFFIX(_ecore_con_ssl_client_read) (Ecore_Con_Client * cl,
+ unsigned char *buf, int size);
+static int SSL_SUFFIX(_ecore_con_ssl_client_write) (Ecore_Con_Client * cl,
+ const unsigned char *buf, int size);
+
+/*
+ * General SSL API
+ */
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_init(void)
+{
+ if (!_init_con_ssl_init_count++)
+ {
+ SSL_SUFFIX(_ecore_con_ssl_init) ();
+#if _ECORE_CON_SSL_AVAILABLE != 0
+ ECORE_CON_EVENT_CLIENT_UPGRADE = ecore_event_type_new();
+ ECORE_CON_EVENT_SERVER_UPGRADE = ecore_event_type_new();
+#endif
+ }
+
+ return _init_con_ssl_init_count;
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_shutdown(void)
+{
+ if (!--_init_con_ssl_init_count)
+ SSL_SUFFIX(_ecore_con_ssl_shutdown) ();
+
+ return _init_con_ssl_init_count;
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_server_prepare(Ecore_Con_Server *svr,
+ int ssl_type)
+{
+ if (!ssl_type)
+ return ECORE_CON_SSL_ERROR_NONE;
+ return SSL_SUFFIX(_ecore_con_ssl_server_prepare) (svr, ssl_type);
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_server_init(Ecore_Con_Server *svr)
+{
+ if (!(svr->type & ECORE_CON_SSL))
+ return ECORE_CON_SSL_ERROR_NONE;
+ return SSL_SUFFIX(_ecore_con_ssl_server_init) (svr);
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr)
+{
+ if (!(svr->type & ECORE_CON_SSL))
+ return ECORE_CON_SSL_ERROR_NONE;
+ return SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (svr);
+}
+
+int
+ecore_con_ssl_server_read(Ecore_Con_Server *svr,
+ unsigned char *buf,
+ int size)
+{
+ return SSL_SUFFIX(_ecore_con_ssl_server_read) (svr, buf, size);
+}
+
+int
+ecore_con_ssl_server_write(Ecore_Con_Server *svr,
+ const unsigned char *buf,
+ int size)
+{
+ return SSL_SUFFIX(_ecore_con_ssl_server_write) (svr, buf, size);
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_client_init(Ecore_Con_Client *cl)
+{
+ if (!(cl->host_server->type & ECORE_CON_SSL))
+ return ECORE_CON_SSL_ERROR_NONE;
+ return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl);
+}
+
+Ecore_Con_Ssl_Error
+ecore_con_ssl_client_shutdown(Ecore_Con_Client *cl)
+{
+ if (!(cl->host_server->type & ECORE_CON_SSL))
+ return ECORE_CON_SSL_ERROR_NONE;
+ return SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (cl);
+}
+
+int
+ecore_con_ssl_client_read(Ecore_Con_Client *cl,
+ unsigned char *buf,
+ int size)
+{
+ return SSL_SUFFIX(_ecore_con_ssl_client_read) (cl, buf, size);
+}
+
+int
+ecore_con_ssl_client_write(Ecore_Con_Client *cl,
+ const unsigned char *buf,
+ int size)
+{
+ return SSL_SUFFIX(_ecore_con_ssl_client_write) (cl, buf, size);
+}
+
+/**
+ * Returns if SSL support is available
+ * @return 1 if SSL is available and provided by gnutls, 2 if provided by openssl,
+ * 0 if it is not available.
+ * @ingroup Ecore_Con_Client_Group
+ */
+EAPI int
+ecore_con_ssl_available_get(void)
+{
+ return _ECORE_CON_SSL_AVAILABLE;
+}
+
+/**
+ * @addtogroup Ecore_Con_SSL_Group Ecore Connection SSL Functions
+ *
+ * Functions that operate on Ecore connection objects pertaining to SSL.
+ *
+ * @{
+ */
+
+/**
+ * @brief Enable certificate verification on a server object
+ *
+ * Call this function on a server object before main loop has started
+ * to enable verification of certificates against loaded certificates.
+ * @param svr The server object
+ */
+EAPI void
+ecore_con_ssl_server_verify(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_verify");
+ return;
+ }
+ svr->verify = EINA_TRUE;
+}
+
+/**
+ * @brief Enable hostname-based certificate verification on a server object
+ *
+ * Call this function on a server object before main loop has started
+ * to enable verification of certificates using ONLY their hostnames.
+ * @param svr The server object
+ * @note This function has no effect when used on a listening server created by
+ * ecore_con_server_add
+ * @since 1.1
+ */
+EAPI void
+ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return;
+ }
+ svr->verify_basic = EINA_TRUE;
+}
+
+/**
+ * @brief Set the hostname to verify against in certificate verification
+ *
+ * Sometimes the certificate hostname will not match the hostname that you are
+ * connecting to, and will instead match a different name. An example of this is
+ * that if you connect to talk.google.com to use Google Talk, you receive Google's
+ * certificate for gmail.com. This certificate should be trusted, and so you must call
+ * this function with "gmail.com" as @p name.
+ * See RFC2818 for more details.
+ * @param svr The server object
+ * @param name The hostname to verify against
+ * @since 1.2
+ */
+EAPI void
+ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return;
+ }
+ eina_stringshare_replace(&svr->verify_name, name);
+}
+
+/**
+ * @brief Get the hostname to verify against in certificate verification
+ *
+ * This function returns the name which will be used to validate the SSL certificate
+ * common name (CN) or alt name (subjectAltName). It will default to the @p name
+ * param in ecore_con_server_connect(), but can be changed with ecore_con_ssl_server_verify_name_set().
+ * @param svr The server object
+ * @return The hostname which will be used
+ * @since 1.2
+ */
+EAPI const char *
+ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return NULL;
+ }
+ return svr->verify_name ?: svr->name;
+}
+
+/**
+ * @brief Add an ssl certificate for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM certificate.
+ * Simply specify the cert here to use it in the server object for connecting or listening.
+ * If there is an error loading the certificate, an error will automatically be logged.
+ * @param svr The server object
+ * @param cert The path to the certificate.
+ * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr,
+ const char *cert)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cert_add");
+ return EINA_FALSE;
+ }
+
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
+ return SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (svr, cert);
+}
+
+/**
+ * @brief Add an ssl CA file for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM CA file.
+ * Simply specify the file here to use it in the server object for connecting or listening.
+ * If there is an error loading the CAs, an error will automatically be logged.
+ * @param svr The server object
+ * @param ca_file The path to the CA file.
+ * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE.
+ * @note since 1.2, this function can load directores
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr,
+ const char *ca_file)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cafile_add");
+ return EINA_FALSE;
+ }
+
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
+ return SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (svr, ca_file);
+}
+
+/**
+ * @brief Add an ssl private key for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM private key
+ * Simply specify the key file here to use it in the server object for connecting or listening.
+ * If there is an error loading the key, an error will automatically be logged.
+ * @param svr The server object
+ * @param key_file The path to the key file.
+ * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr,
+ const char *key_file)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_privkey_add");
+ return EINA_FALSE;
+ }
+
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
+ return SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (svr, key_file);
+}
+
+/**
+ * @brief Add an ssl CRL for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM CRL file
+ * Simply specify the CRL file here to use it in the server object for connecting or listening.
+ * If there is an error loading the CRL, an error will automatically be logged.
+ * @param svr The server object
+ * @param crl_file The path to the CRL file.
+ * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr,
+ const char *crl_file)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_crl_add");
+ return EINA_FALSE;
+ }
+
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
+ return SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (svr, crl_file);
+}
+
+/**
+ * @brief Upgrade a connection to a specified level of encryption
+ *
+ * Use this function to begin an SSL handshake on a connection (STARTTLS or similar).
+ * Once the upgrade has been completed, an ECORE_CON_EVENT_SERVER_UPGRADE event will be emitted.
+ * The connection should be treated as disconnected until the next event.
+ * @param svr The server object
+ * @param ssl_type The SSL connection type (ONLY).
+ * @return @c EINA_FALSE if the connection cannot be upgraded, otherwise @c EINA_TRUE.
+ * @note This function is NEVER to be used on a server object created with ecore_con_server_add
+ * @warning Setting a wrong value for @p compl_type WILL mess up your program.
+ * @since 1.1
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type ssl_type)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return EINA_FALSE;
+ }
+#if _ECORE_CON_SSL_AVAILABLE == 0
+ return EINA_FALSE;
+#endif
+
+ if (!svr->ssl_prepared)
+ {
+ if (ecore_con_ssl_server_prepare(svr, ssl_type))
+ return EINA_FALSE;
+ }
+ if (!svr->use_cert)
+ svr->type |= ssl_type;
+ svr->upgrade = EINA_TRUE;
+ svr->handshaking = EINA_TRUE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_INIT;
+ return !SSL_SUFFIX(_ecore_con_ssl_server_init) (svr);
+}
+
+/**
+ * @brief Upgrade a connection to a specified level of encryption
+ *
+ * Use this function to begin an SSL handshake on a connection (STARTTLS or similar).
+ * Once the upgrade has been completed, an ECORE_CON_EVENT_CLIENT_UPGRADE event will be emitted.
+ * The connection should be treated as disconnected until the next event.
+ * @param cl The client object
+ * @param ssl_type The SSL connection type (ONLY).
+ * @return @c EINA_FALSE if the connection cannot be upgraded, otherwise @c EINA_TRUE.
+ * @warning Setting a wrong value for @p compl_type WILL mess up your program.
+ * @since 1.1
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type ssl_type)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__);
+ return EINA_FALSE;
+ }
+#if _ECORE_CON_SSL_AVAILABLE == 0
+ return EINA_FALSE;
+#endif
+
+ if (!cl->host_server->ssl_prepared)
+ {
+ if (ecore_con_ssl_server_prepare(cl->host_server, ssl_type))
+ return EINA_FALSE;
+ }
+ if (!cl->host_server->use_cert)
+ cl->host_server->type |= ssl_type;
+ cl->upgrade = EINA_TRUE;
+ cl->host_server->upgrade = EINA_TRUE;
+ cl->handshaking = EINA_TRUE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_INIT;
+ return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl);
+}
+
+/**
+ * @}
+ */
+
+#if USE_GNUTLS
+
+/*
+ * GnuTLS
+ */
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_init_gnutls(void)
+{
+#ifdef EINA_HAVE_THREADS
+ if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
+ WRN("YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
+#endif
+ if (gnutls_global_init())
+ return ECORE_CON_SSL_ERROR_INIT_FAILED;
+
+#ifdef ISCOMFITOR
+ if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))
+ {
+ gnutls_global_set_log_level(9);
+ gnutls_global_set_log_function(_gnutls_log_func);
+ }
+#endif
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_shutdown_gnutls(void)
+{
+ gnutls_global_deinit();
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr,
+ int ssl_type)
+{
+ int ret;
+
+ if (ssl_type & ECORE_CON_USE_SSL2)
+ return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
+
+ switch (ssl_type)
+ {
+ case ECORE_CON_USE_SSL3:
+ case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
+ case ECORE_CON_USE_TLS:
+ case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
+ case ECORE_CON_USE_MIXED:
+ case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
+ break;
+
+ default:
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_allocate_credentials(&svr->cert));
+
+ if (svr->use_cert)
+ {
+ if (svr->created)
+ {
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_init(&svr->dh_params));
+ INF("Generating DH params");
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_generate2(svr->dh_params, 1024));
+
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_server_credentials(&svr->anoncred_s));
+ /* TODO: implement PSK */
+ // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_server_credentials(&svr->pskcred_s));
+
+ gnutls_anon_set_server_dh_params(svr->anoncred_s, svr->dh_params);
+ gnutls_certificate_set_dh_params(svr->cert, svr->dh_params);
+ //gnutls_psk_set_server_dh_params(svr->pskcred_s, svr->dh_params);
+ INF("DH params successfully generated and applied!");
+ }
+ else
+ {
+ //SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_client_credentials(&svr->pskcred_c));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_client_credentials(&svr->anoncred_c));
+ }
+ }
+
+ svr->ssl_prepared = EINA_TRUE;
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ _gnutls_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR, ret);
+ _ecore_con_ssl_server_shutdown_gnutls(svr);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr)
+{
+ const gnutls_datum_t *cert_list;
+ unsigned int iter, cert_list_size;
+ gnutls_x509_crt_t cert = NULL;
+ const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0";
+ int ret = 0;
+
+ switch (svr->ssl_state)
+ {
+ case ECORE_CON_SSL_STATE_DONE:
+ return ECORE_CON_SSL_ERROR_NONE;
+
+ case ECORE_CON_SSL_STATE_INIT:
+ if (svr->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
+ return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
+
+ switch (svr->type & ECORE_CON_SSL)
+ {
+ case ECORE_CON_USE_SSL3:
+ case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
+ priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1";
+ break;
+
+ case ECORE_CON_USE_TLS:
+ case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
+ priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0";
+ break;
+
+ case ECORE_CON_USE_MIXED:
+ case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
+ break;
+
+ default:
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_client(svr->session));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_server_name_set(svr->session, GNUTLS_NAME_DNS, svr->name, strlen(svr->name)));
+ INF("Applying priority string: %s", priority);
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(svr->session, priority, NULL));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert));
+ // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c));
+ if (!svr->use_cert)
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c));
+
+ gnutls_dh_set_prime_bits(svr->session, 512);
+ gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)((intptr_t)svr->fd));
+ svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+
+ case ECORE_CON_SSL_STATE_HANDSHAKING:
+ if (!svr->session)
+ {
+ DBG("Server was previously lost, going to error condition");
+ goto error;
+ }
+ ret = gnutls_handshake(svr->session);
+ DBG("calling gnutls_handshake(): returned with '%s'", gnutls_strerror_name(ret));
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));
+ if (!ret)
+ {
+ svr->handshaking = EINA_FALSE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_DONE;
+ }
+ else
+ {
+ if (gnutls_record_get_direction(svr->session))
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ else
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ default:
+ break;
+ }
+
+ if ((!svr->verify) && (!svr->verify_basic))
+ /* not verifying certificates, so we're done! */
+ return ECORE_CON_SSL_ERROR_NONE;
+ if (svr->verify)
+ {
+ /* use CRL/CA lists to verify */
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(svr->session, &iter));
+ if (iter & GNUTLS_CERT_INVALID)
+ ERR("The certificate is not trusted.");
+ else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ ERR("The certificate hasn't got a known issuer.");
+ else if (iter & GNUTLS_CERT_REVOKED)
+ ERR("The certificate has been revoked.");
+ else if (iter & GNUTLS_CERT_EXPIRED)
+ ERR("The certificate has expired");
+ else if (iter & GNUTLS_CERT_NOT_ACTIVATED)
+ ERR("The certificate is not yet activated");
+
+ if (iter)
+ goto error;
+ }
+ if (gnutls_certificate_type_get(svr->session) != GNUTLS_CRT_X509)
+ {
+ ERR("Warning: PGP certificates are not yet supported!");
+ goto error;
+ }
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(svr->session, &cert_list_size)));
+ SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);
+
+ _gnutls_print_session(cert_list, cert_list_size);
+
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->verify_name ?: svr->name));
+ gnutls_x509_crt_deinit(cert);
+ DBG("SSL certificate verification succeeded!");
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ _gnutls_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR, ret);
+ if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
+ ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(svr->session)));
+ if (svr->session && (svr->ssl_state != ECORE_CON_SSL_STATE_DONE))
+ {
+ ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session)));
+ ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session)));
+ }
+ if (cert)
+ gnutls_x509_crt_deinit(cert);
+ _ecore_con_ssl_server_shutdown_gnutls(svr);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cafile_add_gnutls(Ecore_Con_Server *svr,
+ const char *ca_file)
+{
+ struct stat st;
+ Eina_Iterator *it;
+ const char *file;
+ Eina_Bool error = EINA_FALSE;
+
+ if (stat(ca_file, &st)) return EINA_FALSE;
+ if (S_ISDIR(st.st_mode))
+ {
+ it = eina_file_ls(ca_file);
+ SSL_ERROR_CHECK_GOTO_ERROR(!it);
+ EINA_ITERATOR_FOREACH(it, file)
+ {
+ if (!error)
+ {
+ if (gnutls_certificate_set_x509_trust_file(svr->cert, file, GNUTLS_X509_FMT_PEM) < 1)
+ error++;
+ }
+ eina_stringshare_del(file);
+ }
+ eina_iterator_free(it);
+ }
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file,
+ GNUTLS_X509_FMT_PEM) < 1);
+
+ return !error;
+error:
+ ERR("Could not load CA file!");
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_gnutls(Ecore_Con_Server *svr,
+ const char *crl_file)
+{
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_crl_file(svr->cert, crl_file,
+ GNUTLS_X509_FMT_PEM) < 1);
+
+ return EINA_TRUE;
+error:
+ ERR("Could not load CRL file!");
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_gnutls(Ecore_Con_Server *svr,
+ const char *key_file)
+{
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_key_file(svr->cert, svr->cert_file, key_file,
+ GNUTLS_X509_FMT_PEM));
+
+ return EINA_TRUE;
+error:
+ ERR("Could not load certificate/key file!");
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_gnutls(Ecore_Con_Server *svr,
+ const char *cert_file)
+{
+ if (!(svr->cert_file = strdup(cert_file)))
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr)
+{
+ if (svr->session)
+ {
+ gnutls_bye(svr->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(svr->session);
+ }
+
+ free(svr->cert_file);
+ svr->cert_file = NULL;
+ if (svr->cert)
+ gnutls_certificate_free_credentials(svr->cert);
+ svr->cert = NULL;
+
+ if ((svr->type & ECORE_CON_SSL) && svr->created)
+ {
+ if (svr->dh_params)
+ {
+ gnutls_dh_params_deinit(svr->dh_params);
+ svr->dh_params = NULL;
+ }
+ if (svr->anoncred_s)
+ gnutls_anon_free_server_credentials(svr->anoncred_s);
+ // if (svr->pskcred_s)
+ // gnutls_psk_free_server_credentials(svr->pskcred_s);
+
+ svr->anoncred_s = NULL;
+ svr->pskcred_s = NULL;
+ }
+ else if (svr->type & ECORE_CON_SSL)
+ {
+ if (svr->anoncred_c)
+ gnutls_anon_free_client_credentials(svr->anoncred_c);
+ // if (svr->pskcred_c)
+ // gnutls_psk_free_client_credentials(svr->pskcred_c);
+
+ svr->anoncred_c = NULL;
+ svr->pskcred_c = NULL;
+ }
+
+ svr->session = NULL;
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static int
+_ecore_con_ssl_server_read_gnutls(Ecore_Con_Server *svr,
+ unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING)
+ {
+ DBG("Continuing gnutls handshake");
+ if (!_ecore_con_ssl_server_init_gnutls(svr))
+ return 0;
+ return -1;
+ }
+
+ num = gnutls_record_recv(svr->session, buf, size);
+ if (num > 0)
+ return num;
+
+ if (num == GNUTLS_E_REHANDSHAKE)
+ {
+ WRN("Rehandshake request ignored");
+ return 0;
+
+ svr->handshaking = EINA_TRUE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+ if (!_ecore_con_ssl_server_init_gnutls(svr))
+ return 0;
+ }
+ else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS))
+ return 0;
+
+ return -1;
+}
+
+static int
+_ecore_con_ssl_server_write_gnutls(Ecore_Con_Server *svr,
+ const unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING)
+ {
+ DBG("Continuing gnutls handshake");
+ if (!_ecore_con_ssl_server_init_gnutls(svr))
+ return 0;
+ return -1;
+ }
+
+ num = gnutls_record_send(svr->session, buf, size);
+ if (num > 0)
+ return num;
+
+ if (num == GNUTLS_E_REHANDSHAKE)
+ {
+ WRN("Rehandshake request ignored");
+ return 0;
+/* this is only partly functional I think? */
+ svr->handshaking = EINA_TRUE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+ if (!_ecore_con_ssl_server_init_gnutls(svr))
+ return 0;
+ }
+ else if (!gnutls_error_is_fatal(num))
+ return 0;
+
+ return -1;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl)
+{
+ const gnutls_datum_t *cert_list;
+ unsigned int iter, cert_list_size;
+ const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0";
+ int ret = 0;
+
+ switch (cl->ssl_state)
+ {
+ case ECORE_CON_SSL_STATE_DONE:
+ return ECORE_CON_SSL_ERROR_NONE;
+
+ case ECORE_CON_SSL_STATE_INIT:
+ if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
+ return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
+
+ switch (cl->host_server->type & ECORE_CON_SSL)
+ {
+ case ECORE_CON_USE_SSL3:
+ case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
+ priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1";
+ break;
+
+ case ECORE_CON_USE_TLS:
+ case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
+ priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0";
+ break;
+
+ case ECORE_CON_USE_MIXED:
+ case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
+ break;
+
+ default:
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ _client_connected++;
+
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_key_generate(&cl->session_ticket));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_server(cl->session, &cl->session_ticket));
+ INF("Applying priority string: %s", priority);
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(cl->session, priority, NULL));
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert));
+ // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s));
+ if (!cl->host_server->use_cert)
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s));
+
+ gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST);
+
+ gnutls_dh_set_prime_bits(cl->session, 2048);
+ gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)((intptr_t)cl->fd));
+ cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+
+ case ECORE_CON_SSL_STATE_HANDSHAKING:
+ if (!cl->session)
+ {
+ DBG("Client was previously lost, going to error condition");
+ goto error;
+ }
+ DBG("calling gnutls_handshake()");
+ ret = gnutls_handshake(cl->session);
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));
+
+ if (!ret)
+ {
+ cl->handshaking = EINA_FALSE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
+ }
+ else
+ {
+ if (gnutls_record_get_direction(cl->session))
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
+ else
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ default:
+ break;
+ }
+
+ if (!cl->host_server->verify)
+ /* not verifying certificates, so we're done! */
+ return ECORE_CON_SSL_ERROR_NONE;
+ /* use CRL/CA lists to verify */
+ SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(cl->session, &iter));
+ if (iter & GNUTLS_CERT_INVALID)
+ ERR("The certificate is not trusted.");
+ else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ ERR("The certificate hasn't got a known issuer.");
+ else if (iter & GNUTLS_CERT_REVOKED)
+ ERR("The certificate has been revoked.");
+ else if (iter & GNUTLS_CERT_EXPIRED)
+ ERR("The certificate has expired");
+ else if (iter & GNUTLS_CERT_NOT_ACTIVATED)
+ ERR("The certificate is not yet activated");
+
+ if (iter)
+ goto error;
+ if (gnutls_certificate_type_get(cl->session) != GNUTLS_CRT_X509)
+ {
+ ERR("Warning: PGP certificates are not yet supported!");
+ goto error;
+ }
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size)));
+ SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);
+
+ _gnutls_print_session(cert_list, cert_list_size);
+/*
+ gnutls_x509_crt_t cert = NULL;
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, cl->host_server->name));
+ gnutls_x509_crt_deinit(cert);
+*/
+ DBG("SSL certificate verification succeeded!");
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ _gnutls_print_errors(cl, ECORE_CON_EVENT_CLIENT_ERROR, ret);
+ if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
+ ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session)));
+ if (cl->session && (cl->ssl_state != ECORE_CON_SSL_STATE_DONE))
+ {
+ ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session)));
+ ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(cl->session)));
+ }
+/*
+ if (cert)
+ gnutls_x509_crt_deinit(cert);
+*/
+ _ecore_con_ssl_client_shutdown_gnutls(cl);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_shutdown_gnutls(Ecore_Con_Client *cl)
+{
+ if (cl->session)
+ {
+ gnutls_bye(cl->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(cl->session);
+ gnutls_free(cl->session_ticket.data);
+ cl->session_ticket.data = NULL;
+ }
+
+ cl->session = NULL;
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static int
+_ecore_con_ssl_client_read_gnutls(Ecore_Con_Client *cl,
+ unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING)
+ {
+ if (!_ecore_con_ssl_client_init_gnutls(cl))
+ return 0;
+ return -1;
+ }
+
+ num = gnutls_record_recv(cl->session, buf, size);
+ if (num > 0)
+ return num;
+
+ if (num == GNUTLS_E_REHANDSHAKE)
+ {
+ WRN("Rehandshake request ignored");
+ return 0;
+ cl->handshaking = EINA_TRUE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+ if (!_ecore_con_ssl_client_init_gnutls(cl))
+ return 0;
+ WRN("Rehandshake request ignored");
+ return 0;
+ }
+ else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS))
+ return 0;
+
+ return -1;
+}
+
+static int
+_ecore_con_ssl_client_write_gnutls(Ecore_Con_Client *cl,
+ const unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING)
+ {
+ if (!_ecore_con_ssl_client_init_gnutls(cl))
+ return 0;
+ return -1;
+ }
+
+ num = gnutls_record_send(cl->session, buf, size);
+ if (num > 0)
+ return num;
+
+ if (num == GNUTLS_E_REHANDSHAKE)
+ {
+ WRN("Rehandshake request ignored");
+ return 0;
+ cl->handshaking = EINA_TRUE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+ if (!_ecore_con_ssl_client_init_gnutls(cl))
+ return 0;
+ }
+ else if (!gnutls_error_is_fatal(num))
+ return 0;
+
+ return -1;
+}
+
+#elif USE_OPENSSL && !USE_GNUTLS
+
+/*
+ * OpenSSL
+ */
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_init_openssl(void)
+{
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_shutdown_openssl(void)
+{
+ ERR_free_strings();
+ EVP_cleanup();
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *svr,
+ int ssl_type)
+{
+ long options;
+ int dh = 0;
+
+ if (ssl_type & ECORE_CON_USE_SSL2)
+ return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
+
+ switch (ssl_type)
+ {
+ case ECORE_CON_USE_SSL3:
+ case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
+ if (!svr->created)
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())));
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_server_method())));
+ break;
+
+ case ECORE_CON_USE_TLS:
+ case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
+ if (!svr->created)
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())));
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_server_method())));
+ break;
+
+ case ECORE_CON_USE_MIXED:
+ case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
+ if (!svr->created)
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_client_method())));
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_server_method())));
+ options = SSL_CTX_get_options(svr->ssl_ctx);
+ SSL_CTX_set_options(svr->ssl_ctx, options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE);
+ break;
+
+ default:
+ svr->ssl_prepared = EINA_TRUE;
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ if ((!svr->use_cert) && svr->created)
+ {
+ DH *dh_params;
+ INF("Generating DH params");
+ SSL_ERROR_CHECK_GOTO_ERROR(!(dh_params = DH_new()));
+ SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_parameters_ex(dh_params, 1024, DH_GENERATOR_5, NULL));
+ SSL_ERROR_CHECK_GOTO_ERROR(!DH_check(dh_params, &dh));
+ SSL_ERROR_CHECK_GOTO_ERROR((dh & DH_CHECK_P_NOT_PRIME) || (dh & DH_CHECK_P_NOT_SAFE_PRIME));
+ SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_key(dh_params));
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_tmp_dh(svr->ssl_ctx, dh_params));
+ DH_free(dh_params);
+ INF("DH params successfully generated and applied!");
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:@STRENGTH"));
+ }
+ else if (!svr->use_cert)
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:!ECDH:RSA:AES:!PSK:@STRENGTH"));
+
+ svr->ssl_prepared = EINA_TRUE;
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ if (dh)
+ {
+ if (dh & DH_CHECK_P_NOT_PRIME)
+ ERR("openssl error: dh_params could not generate a prime!");
+ else
+ ERR("openssl error: dh_params could not generate a safe prime!");
+ }
+ else
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ _ecore_con_ssl_server_shutdown_openssl(svr);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr)
+{
+ int ret = -1;
+
+ switch (svr->ssl_state)
+ {
+ case ECORE_CON_SSL_STATE_DONE:
+ return ECORE_CON_SSL_ERROR_NONE;
+
+ case ECORE_CON_SSL_STATE_INIT:
+ SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl = SSL_new(svr->ssl_ctx)));
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(svr->ssl, svr->fd));
+ SSL_set_connect_state(svr->ssl);
+ svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+
+ case ECORE_CON_SSL_STATE_HANDSHAKING:
+ if (!svr->ssl)
+ {
+ DBG("Server was previously lost, going to error condition");
+ goto error;
+ }
+ ret = SSL_do_handshake(svr->ssl);
+ svr->ssl_err = SSL_get_error(svr->ssl, ret);
+ SSL_ERROR_CHECK_GOTO_ERROR((svr->ssl_err == SSL_ERROR_SYSCALL) || (svr->ssl_err == SSL_ERROR_SSL));
+
+ if (ret == 1)
+ {
+ svr->handshaking = EINA_FALSE;
+ svr->ssl_state = ECORE_CON_SSL_STATE_DONE;
+ }
+ else
+ {
+ if (svr->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ else if (svr->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ default:
+ break;
+ }
+
+ _openssl_print_session(svr->ssl);
+ if ((!svr->verify) && (!svr->verify_basic))
+ /* not verifying certificates, so we're done! */
+ return ECORE_CON_SSL_ERROR_NONE;
+
+ {
+ X509 *cert;
+ SSL_set_verify(svr->ssl, SSL_VERIFY_PEER, NULL);
+ /* use CRL/CA lists to verify */
+ cert = SSL_get_peer_certificate(svr->ssl);
+ if (cert)
+ {
+ char *c;
+ int clen;
+ int name = 0;
+
+ if (svr->verify)
+ {
+ int err;
+
+ err = SSL_get_verify_result(svr->ssl);
+ _openssl_print_verify_error(err);
+ SSL_ERROR_CHECK_GOTO_ERROR(err);
+ }
+ clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, NULL, 0);
+ if (clen > 0)
+ name = NID_subject_alt_name;
+ else
+ clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, NULL, 0);
+ SSL_ERROR_CHECK_GOTO_ERROR(clen < 1);
+ if (!name) name = NID_commonName;
+ c = alloca(++clen);
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert), name, c, clen);
+ INF("CERT NAME: %s\n", c);
+ SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(c, svr->verify_name ?: svr->name));
+ }
+ }
+
+ DBG("SSL certificate verification succeeded!");
+
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ _ecore_con_ssl_server_shutdown_openssl(svr);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cafile_add_openssl(Ecore_Con_Server *svr,
+ const char *ca_file)
+{
+ struct stat st;
+
+ if (stat(ca_file, &st)) return EINA_FALSE;
+ if (S_ISDIR(st.st_mode))
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, NULL, ca_file));
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL));
+ return EINA_TRUE;
+
+error:
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_openssl(Ecore_Con_Server *svr,
+ const char *crl_file)
+{
+ X509_STORE *st;
+ X509_LOOKUP *lu;
+ static Eina_Bool flag = EINA_FALSE;
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!(st = SSL_CTX_get_cert_store(svr->ssl_ctx)));
+ SSL_ERROR_CHECK_GOTO_ERROR(!(lu = X509_STORE_add_lookup(st, X509_LOOKUP_file())));
+ SSL_ERROR_CHECK_GOTO_ERROR(X509_load_crl_file(lu, crl_file, X509_FILETYPE_PEM) < 1);
+ if (!flag)
+ {
+ X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+ flag = EINA_TRUE;
+ }
+
+ return EINA_TRUE;
+
+error:
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_openssl(Ecore_Con_Server *svr,
+ const char *key_file)
+{
+ FILE *fp = NULL;
+ EVP_PKEY *privkey = NULL;
+
+ if (!(fp = fopen(key_file, "r")))
+ goto error;
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!(privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)));
+
+ fclose(fp);
+ fp = NULL;
+ SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_PrivateKey(svr->ssl_ctx, privkey) < 1);
+ SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_check_private_key(svr->ssl_ctx) < 1);
+
+ return EINA_TRUE;
+
+error:
+ if (fp)
+ fclose(fp);
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_openssl(Ecore_Con_Server *svr,
+ const char *cert_file)
+{
+ FILE *fp = NULL;
+ X509 *cert = NULL;
+
+ if (!(fp = fopen(cert_file, "r")))
+ goto error;
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!(cert = PEM_read_X509(fp, NULL, NULL, NULL)));
+
+ fclose(fp);
+ fp = NULL;
+ SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, cert) < 1);
+
+ return EINA_TRUE;
+
+error:
+ if (fp)
+ fclose(fp);
+ _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR);
+ return EINA_FALSE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_shutdown_openssl(Ecore_Con_Server *svr)
+{
+ if (svr->ssl)
+ {
+ if (!SSL_shutdown(svr->ssl))
+ SSL_shutdown(svr->ssl);
+
+ SSL_free(svr->ssl);
+ }
+
+ if (svr->ssl_ctx)
+ SSL_CTX_free(svr->ssl_ctx);
+
+ svr->ssl = NULL;
+ svr->ssl_ctx = NULL;
+ svr->ssl_err = SSL_ERROR_NONE;
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static int
+_ecore_con_ssl_server_read_openssl(Ecore_Con_Server *svr,
+ unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (!svr->ssl) return -1;
+ num = SSL_read(svr->ssl, buf, size);
+ svr->ssl_err = SSL_get_error(svr->ssl, num);
+
+ if (svr->fd_handler)
+ {
+ if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ }
+
+ if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) ||
+ (svr->ssl_err == SSL_ERROR_SYSCALL) ||
+ (svr->ssl_err == SSL_ERROR_SSL))
+ return -1;
+
+ if (num < 0)
+ return 0;
+
+ return num;
+}
+
+static int
+_ecore_con_ssl_server_write_openssl(Ecore_Con_Server *svr,
+ const unsigned char *buf,
+ int size)
+{
+ int num;
+
+ num = SSL_write(svr->ssl, buf, size);
+ svr->ssl_err = SSL_get_error(svr->ssl, num);
+
+ if (svr->fd_handler)
+ {
+ if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+ else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ }
+
+ if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) ||
+ (svr->ssl_err == SSL_ERROR_SYSCALL) ||
+ (svr->ssl_err == SSL_ERROR_SSL))
+ return -1;
+
+ if (num < 0)
+ return 0;
+
+ return num;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_init_openssl(Ecore_Con_Client *cl)
+{
+ int ret = -1;
+ switch (cl->ssl_state)
+ {
+ case ECORE_CON_SSL_STATE_DONE:
+ return ECORE_CON_SSL_ERROR_NONE;
+
+ case ECORE_CON_SSL_STATE_INIT:
+ SSL_ERROR_CHECK_GOTO_ERROR(!(cl->ssl = SSL_new(cl->host_server->ssl_ctx)));
+
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(cl->ssl, cl->fd));
+ SSL_set_accept_state(cl->ssl);
+ cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
+
+ case ECORE_CON_SSL_STATE_HANDSHAKING:
+ if (!cl->ssl)
+ {
+ DBG("Client was previously lost, going to error condition");
+ goto error;
+ }
+ ret = SSL_do_handshake(cl->ssl);
+ cl->ssl_err = SSL_get_error(cl->ssl, ret);
+ SSL_ERROR_CHECK_GOTO_ERROR((cl->ssl_err == SSL_ERROR_SYSCALL) || (cl->ssl_err == SSL_ERROR_SSL));
+ if (ret == 1)
+ {
+ cl->handshaking = EINA_FALSE;
+ cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
+ }
+ else
+ {
+ if (cl->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ else if (cl->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
+ return ECORE_CON_SSL_ERROR_NONE;
+ }
+
+ default:
+ break;
+ }
+
+ _openssl_print_session(cl->ssl);
+ if (!cl->host_server->verify)
+ /* not verifying certificates, so we're done! */
+ return ECORE_CON_SSL_ERROR_NONE;
+ SSL_set_verify(cl->ssl, SSL_VERIFY_PEER, NULL);
+ /* use CRL/CA lists to verify */
+ if (SSL_get_peer_certificate(cl->ssl))
+ {
+ int err;
+
+ err = SSL_get_verify_result(cl->ssl);
+ _openssl_print_verify_error(err);
+ SSL_ERROR_CHECK_GOTO_ERROR(err);
+ }
+
+ return ECORE_CON_SSL_ERROR_NONE;
+
+error:
+ _openssl_print_errors(cl, ECORE_CON_EVENT_CLIENT_ERROR);
+ _ecore_con_ssl_client_shutdown_openssl(cl);
+ return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_shutdown_openssl(Ecore_Con_Client *cl)
+{
+ if (cl->ssl)
+ {
+ if (!SSL_shutdown(cl->ssl))
+ SSL_shutdown(cl->ssl);
+
+ SSL_free(cl->ssl);
+ }
+
+ cl->ssl = NULL;
+ cl->ssl_err = SSL_ERROR_NONE;
+
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static int
+_ecore_con_ssl_client_read_openssl(Ecore_Con_Client *cl,
+ unsigned char *buf,
+ int size)
+{
+ int num;
+
+ if (!cl->ssl) return -1;
+ num = SSL_read(cl->ssl, buf, size);
+ cl->ssl_err = SSL_get_error(cl->ssl, num);
+
+ if (cl->fd_handler)
+ {
+ if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
+ }
+
+ if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) ||
+ (cl->ssl_err == SSL_ERROR_SYSCALL) ||
+ (cl->ssl_err == SSL_ERROR_SSL))
+ return -1;
+
+ if (num < 0)
+ return 0;
+
+ return num;
+}
+
+static int
+_ecore_con_ssl_client_write_openssl(Ecore_Con_Client *cl,
+ const unsigned char *buf,
+ int size)
+{
+ int num;
+
+ num = SSL_write(cl->ssl, buf, size);
+ cl->ssl_err = SSL_get_error(cl->ssl, num);
+
+ if (cl->fd_handler)
+ {
+ if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+ else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE)
+ ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
+ }
+
+ if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) ||
+ (cl->ssl_err == SSL_ERROR_SYSCALL) ||
+ (cl->ssl_err == SSL_ERROR_SSL))
+ return -1;
+
+ if (num < 0)
+ return 0;
+
+ return num;
+}
+
+#else
+
+/*
+ * No Ssl
+ */
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_init_none(void)
+{
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_shutdown_none(void)
+{
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_prepare_none(Ecore_Con_Server *svr EINA_UNUSED,
+ int ssl_type EINA_UNUSED)
+{
+ return ECORE_CON_SSL_ERROR_NONE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_init_none(Ecore_Con_Server *svr EINA_UNUSED)
+{
+ return ECORE_CON_SSL_ERROR_NOT_SUPPORTED;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cafile_add_none(Ecore_Con_Server *svr EINA_UNUSED,
+ const char *ca_file EINA_UNUSED)
+{
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_none(Ecore_Con_Server *svr EINA_UNUSED,
+ const char *cert_file EINA_UNUSED)
+{
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_none(Ecore_Con_Server *svr EINA_UNUSED,
+ const char *key_file EINA_UNUSED)
+{
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_none(Ecore_Con_Server *svr EINA_UNUSED,
+ const char *crl_file EINA_UNUSED)
+{
+ return EINA_FALSE;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_server_shutdown_none(Ecore_Con_Server *svr EINA_UNUSED)
+{
+ return ECORE_CON_SSL_ERROR_NOT_SUPPORTED;
+}
+
+static int
+_ecore_con_ssl_server_read_none(Ecore_Con_Server *svr EINA_UNUSED,
+ unsigned char *buf EINA_UNUSED,
+ int size EINA_UNUSED)
+{
+ return -1;
+}
+
+static int
+_ecore_con_ssl_server_write_none(Ecore_Con_Server *svr EINA_UNUSED,
+ const unsigned char *buf EINA_UNUSED,
+ int size EINA_UNUSED)
+{
+ return -1;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_init_none(Ecore_Con_Client *cl EINA_UNUSED)
+{
+ return ECORE_CON_SSL_ERROR_NOT_SUPPORTED;
+}
+
+static Ecore_Con_Ssl_Error
+_ecore_con_ssl_client_shutdown_none(Ecore_Con_Client *cl EINA_UNUSED)
+{
+ return ECORE_CON_SSL_ERROR_NOT_SUPPORTED;
+}
+
+static int
+_ecore_con_ssl_client_read_none(Ecore_Con_Client *cl EINA_UNUSED,
+ unsigned char *buf EINA_UNUSED,
+ int size EINA_UNUSED)
+{
+ return -1;
+}
+
+static int
+_ecore_con_ssl_client_write_none(Ecore_Con_Client *cl EINA_UNUSED,
+ const unsigned char *buf EINA_UNUSED,
+ int size EINA_UNUSED)
+{
+ return -1;
+}
+
+#endif
diff --git a/src/lib/ecore_con/ecore_con_url.c b/src/lib/ecore_con/ecore_con_url.c
new file mode 100644
index 0000000000..467f3f113b
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_url.c
@@ -0,0 +1,1683 @@
+/*
+ * For info on how to use libcurl, see:
+ * http://curl.haxx.se/libcurl/c/libcurl-tutorial.html
+ */
+
+/*
+ * FIXME: Support more CURL features...
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_ESCAPE
+# include <Escape.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+#define CURL_MIN_TIMEOUT 100
+
+int ECORE_CON_EVENT_URL_DATA = 0;
+int ECORE_CON_EVENT_URL_COMPLETE = 0;
+int ECORE_CON_EVENT_URL_PROGRESS = 0;
+
+#ifdef HAVE_CURL
+static void _ecore_con_url_event_url_complete(Ecore_Con_Url *url_con, CURLMsg *curlmsg);
+static void _ecore_con_url_multi_remove(Ecore_Con_Url *url_con);
+static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con);
+static size_t _ecore_con_url_header_cb(void *ptr, size_t size, size_t nitems, void *stream);
+static size_t _ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp);
+static int _ecore_con_url_progress_cb(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
+static size_t _ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, void *stream);
+static void _ecore_con_event_url_free(Ecore_Con_Url *url_con, void *ev);
+static Eina_Bool _ecore_con_url_timer(void *data);
+static Eina_Bool _ecore_con_url_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_con_url_timeout_cb(void *data);
+static void _ecore_con_url_status_get(Ecore_Con_Url *url_con);
+
+static Eina_List *_url_con_list = NULL;
+static Eina_List *_fd_hd_list = NULL;
+static CURLM *_curlm = NULL;
+static int _init_count = 0;
+static Ecore_Timer *_curl_timer = NULL;
+static Eina_Bool pipelining = EINA_FALSE;
+static Ecore_Idler *_curl_idler = NULL;
+#endif
+
+/**
+ * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions
+ *
+ * @{
+ */
+
+EAPI int
+ecore_con_url_init(void)
+{
+#ifdef HAVE_CURL
+ long ms;
+ if (++_init_count > 1) return _init_count;
+
+ ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
+ ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new();
+ ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new();
+
+ // curl_global_init() is not thread safe!
+ if (curl_global_init(CURL_GLOBAL_ALL)) return --_init_count;
+
+ _curlm = curl_multi_init();
+ if (!_curlm)
+ {
+ curl_global_cleanup();
+ return --_init_count;
+ }
+
+ curl_multi_timeout(_curlm, &ms);
+ if ((ms >= CURL_MIN_TIMEOUT) || (ms <= 0)) ms = CURL_MIN_TIMEOUT;
+
+ _curl_timer = ecore_timer_add((double)ms / 1000.0,
+ _ecore_con_url_timer, NULL);
+ ecore_timer_freeze(_curl_timer);
+
+ return _init_count;
+#else
+ return 0;
+#endif
+}
+
+EAPI int
+ecore_con_url_shutdown(void)
+{
+#ifdef HAVE_CURL
+ Ecore_Con_Url *url_con;
+ Ecore_Fd_Handler *fd_handler;
+ if (_init_count == 0) return 0;
+ --_init_count;
+ if (_init_count) return _init_count;
+
+ if (_curl_timer)
+ {
+ ecore_timer_del(_curl_timer);
+ _curl_timer = NULL;
+ }
+
+ if (_curl_idler)
+ {
+ ecore_idler_del(_curl_idler);
+ _curl_idler = NULL;
+ }
+
+ EINA_LIST_FREE(_url_con_list, url_con)
+ ecore_con_url_free(url_con);
+ EINA_LIST_FREE(_fd_hd_list, fd_handler)
+ ecore_main_fd_handler_del(fd_handler);
+
+ if (_curlm)
+ {
+ curl_multi_cleanup(_curlm);
+ _curlm = NULL;
+ }
+ curl_global_cleanup();
+ return 0;
+#endif
+ return 1;
+}
+
+EAPI void
+ecore_con_url_pipeline_set(Eina_Bool enable)
+{
+#ifdef HAVE_CURL
+ if (enable == pipelining) return;
+ curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, !!enable);
+ pipelining = enable;
+#else
+ return;
+ (void)enable;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_pipeline_get(void)
+{
+#ifdef HAVE_CURL
+ return pipelining;
+#endif
+ return EINA_FALSE;
+}
+
+extern Ecore_Con_Socks *_ecore_con_proxy_global;
+
+EAPI Ecore_Con_Url *
+ecore_con_url_new(const char *url)
+{
+#ifdef HAVE_CURL
+ Ecore_Con_Url *url_con;
+ CURLcode ret;
+
+ if (!_init_count)
+ return NULL;
+
+ url_con = calloc(1, sizeof(Ecore_Con_Url));
+ if (!url_con)
+ return NULL;
+
+ url_con->write_fd = -1;
+
+ url_con->curl_easy = curl_easy_init();
+ if (!url_con->curl_easy)
+ {
+ free(url_con);
+ return NULL;
+ }
+
+ ECORE_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL);
+
+ if (!ecore_con_url_url_set(url_con, url))
+ {
+ ecore_con_url_free(url_con);
+ return NULL;
+ }
+
+ // Read socks proxy
+ url_con->proxy_type = -1;
+ if (_ecore_con_proxy_global && _ecore_con_proxy_global->ip &&
+ (_ecore_con_proxy_global->version == 4 ||
+ _ecore_con_proxy_global->version == 5))
+ {
+ char proxy[256];
+ char host[256];
+
+ if (_ecore_con_proxy_global->version == 5)
+ {
+ if (_ecore_con_proxy_global->lookup)
+ snprintf(host, sizeof(host), "socks5h://%s",
+ _ecore_con_proxy_global->ip);
+ else snprintf(host, sizeof(host), "socks5://%s",
+ _ecore_con_proxy_global->ip);
+ }
+ else if (_ecore_con_proxy_global->version == 4)
+ {
+ if (_ecore_con_proxy_global->lookup)
+ snprintf(host, sizeof(host), "socks4a://%s",
+ _ecore_con_proxy_global->ip);
+ else snprintf(host, sizeof(host), "socks4://%s",
+ _ecore_con_proxy_global->ip);
+ }
+
+ if (_ecore_con_proxy_global->port > 0 &&
+ _ecore_con_proxy_global->port <= 65535)
+ snprintf(proxy, sizeof(proxy), "%s:%d", host,
+ _ecore_con_proxy_global->port);
+ else snprintf(proxy, sizeof(proxy), "%s", host);
+
+ ecore_con_url_proxy_set(url_con, proxy);
+ ecore_con_url_proxy_username_set(url_con,
+ _ecore_con_proxy_global->username);
+ }
+
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate");
+ if (ret != CURLE_OK)
+ {
+ ERR("Could not set CURLOPT_ENCODING to \"gzip,deflate\": %s",
+ curl_easy_strerror(ret));
+ ecore_con_url_free(url_con);
+ return NULL;
+ }
+
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEFUNCTION,
+ _ecore_con_url_data_cb);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEDATA, url_con);
+
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION,
+ _ecore_con_url_progress_cb);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSDATA, url_con);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_FALSE);
+
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERFUNCTION,
+ _ecore_con_url_header_cb);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERDATA, url_con);
+
+ /*
+ * FIXME: Check that these timeouts are sensible defaults
+ * FIXME: Provide a means to change these timeouts
+ */
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1);
+
+ return url_con;
+#else
+ return NULL;
+ url = NULL;
+#endif
+}
+
+EAPI Ecore_Con_Url *
+ecore_con_url_custom_new(const char *url,
+ const char *custom_request)
+{
+#ifdef HAVE_CURL
+ Ecore_Con_Url *url_con;
+ CURLcode ret;
+
+ if (!url)
+ return NULL;
+
+ if (!custom_request)
+ return NULL;
+
+ url_con = ecore_con_url_new(url);
+
+ if (!url_con)
+ return NULL;
+
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_CUSTOMREQUEST, custom_request);
+ if (ret != CURLE_OK)
+ {
+ ERR("Could not set a custom request string: %s",
+ curl_easy_strerror(ret));
+ ecore_con_url_free(url_con);
+ return NULL;
+ }
+
+ return url_con;
+#else
+ return NULL;
+ url = NULL;
+ custom_request = NULL;
+#endif
+}
+
+EAPI void
+ecore_con_url_free(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ char *s;
+
+ if (!url_con) return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_free");
+ return;
+ }
+
+ if (url_con->curl_easy)
+ {
+ // FIXME : How can we delete curl_easy's fds ?? (Curl do not give this info.)
+ // This cause "Failed to delete epoll fd xx!" error messages
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE);
+
+ if (url_con->multi)
+ {
+ _ecore_con_url_multi_remove(url_con);
+ _url_con_list = eina_list_remove(_url_con_list, url_con);
+ }
+
+ curl_easy_cleanup(url_con->curl_easy);
+ }
+ if (url_con->timer) ecore_timer_del(url_con->timer);
+
+ url_con->curl_easy = NULL;
+ url_con->timer = NULL;
+ url_con->dead = EINA_TRUE;
+ if (url_con->event_count) return;
+ ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE);
+
+ curl_slist_free_all(url_con->headers);
+ EINA_LIST_FREE(url_con->additional_headers, s)
+ free(s);
+ EINA_LIST_FREE(url_con->response_headers, s)
+ free(s);
+ eina_stringshare_del(url_con->url);
+ if (url_con->post_data) free(url_con->post_data);
+ free(url_con);
+#else
+ return;
+ (void)url_con;
+#endif
+}
+
+EAPI const char *
+ecore_con_url_url_get(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__);
+ return NULL;
+ }
+ return url_con->url;
+#else
+ return NULL;
+ (void)url_con;
+#endif
+}
+
+EAPI int
+ecore_con_url_status_code_get(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__);
+ return 0;
+ }
+
+ if (url_con->status) return url_con->status;
+ _ecore_con_url_status_get(url_con);
+ return url_con->status;
+#else
+ return -1;
+ (void)url_con;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_url_set(Ecore_Con_Url *url_con, const char *url)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_url_set");
+ return EINA_FALSE;
+ }
+
+ if (url_con->dead) return EINA_FALSE;
+ eina_stringshare_replace(&url_con->url, url);
+
+ if (url_con->url)
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_URL,
+ url_con->url);
+ else
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, "");
+
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url;
+ (void)url_con;
+#endif
+}
+
+EAPI void
+ecore_con_url_data_set(Ecore_Con_Url *url_con, void *data)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_set");
+ return;
+ }
+
+ url_con->data = data;
+#else
+ return;
+ url_con = NULL;
+ data = NULL;
+#endif
+}
+
+EAPI void
+ecore_con_url_additional_header_add(Ecore_Con_Url *url_con, const char *key, const char *value)
+{
+#ifdef HAVE_CURL
+ char *tmp;
+
+ if (url_con->dead) return;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_additional_header_add");
+ return;
+ }
+
+ if (url_con->dead) return;
+ tmp = malloc(strlen(key) + strlen(value) + 3);
+ if (!tmp)
+ return;
+
+ sprintf(tmp, "%s: %s", key, value);
+ url_con->additional_headers = eina_list_append(url_con->additional_headers,
+ tmp);
+#else
+ return;
+ url_con = NULL;
+ key = NULL;
+ value = NULL;
+#endif
+}
+
+EAPI void
+ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ char *s;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_additional_headers_clear");
+ return;
+ }
+
+ EINA_LIST_FREE(url_con->additional_headers, s)
+ free(s);
+#else
+ return;
+ url_con = NULL;
+#endif
+}
+
+EAPI void *
+ecore_con_url_data_get(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_get");
+ return NULL;
+ }
+
+ return url_con->data;
+#else
+ return NULL;
+ url_con = NULL;
+#endif
+}
+
+EAPI void
+ecore_con_url_time(Ecore_Con_Url *url_con, Ecore_Con_Url_Time condition, double timestamp)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_time");
+ return;
+ }
+
+ if (url_con->dead) return;
+ url_con->time_condition = condition;
+ url_con->timestamp = timestamp;
+#else
+ return;
+ (void)url_con;
+ (void)condition;
+ (void)timestamp;
+#endif
+}
+
+EAPI void
+ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_set");
+ return;
+ }
+
+ if (url_con->dead) return;
+ url_con->write_fd = fd;
+#else
+ return;
+ (void)url_con;
+ (void)fd;
+#endif
+}
+
+EAPI int
+ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_received_bytes_get");
+ return -1;
+ }
+
+ return url_con->received;
+#else
+ return 0;
+ (void)url_con;
+#endif
+}
+
+EAPI const Eina_List *
+ecore_con_url_response_headers_get(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ return url_con->response_headers;
+#else
+ return NULL;
+ (void)url_con;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_httpauth_set(Ecore_Con_Url *url_con, const char *username, const char *password, Eina_Bool safe)
+{
+#ifdef HAVE_CURL
+ CURLcode ret;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_httpauth_set");
+ return EINA_FALSE;
+ }
+
+ if (url_con->dead) return EINA_FALSE;
+# if LIBCURL_VERSION_NUM >= 0x071301
+ if ((username) && (password))
+ {
+ if (safe)
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH,
+ CURLAUTH_ANYSAFE);
+ else
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
+ if (ret != CURLE_OK)
+ {
+ ERR("Could not set username for HTTP authentication: %s",
+ curl_easy_strerror(ret));
+ return EINA_FALSE;
+ }
+
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
+ if (ret != CURLE_OK)
+ {
+ ERR("Could not set password for HTTP authentication: %s",
+ curl_easy_strerror(ret));
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+ }
+# endif
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)username;
+ (void)password;
+ (void)safe;
+#endif
+
+ return EINA_FALSE;
+}
+
+#define MODE_AUTO 0
+#define MODE_GET 1
+#define MODE_POST 2
+
+static Eina_Bool
+_ecore_con_url_send(Ecore_Con_Url *url_con, int mode, const void *data, long length, const char *content_type)
+{
+#ifdef HAVE_CURL
+ Eina_List *l;
+ const char *s;
+ char tmp[512];
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_send");
+ return EINA_FALSE;
+ }
+
+ if (!url_con->url) return EINA_FALSE;
+ if (url_con->dead) return EINA_FALSE;
+
+ /* Free response headers from previous send() calls */
+ EINA_LIST_FREE(url_con->response_headers, s)
+ free((char *)s);
+ url_con->response_headers = NULL;
+ url_con->status = 0;
+
+ curl_slist_free_all(url_con->headers);
+ url_con->headers = NULL;
+
+ if ((mode == MODE_POST) || (mode == MODE_AUTO))
+ {
+ if (url_con->post_data) free(url_con->post_data);
+ url_con->post_data = NULL;
+ if ((data) && (length > 0))
+ {
+ url_con->post_data = malloc(length);
+ if (url_con->post_data)
+ {
+ memcpy(url_con->post_data, data, length);
+ if ((content_type) && (strlen(content_type) < 450))
+ {
+ snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type);
+ url_con->headers = curl_slist_append(url_con->headers, tmp);
+ }
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, url_con->post_data);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length);
+ }
+ else
+ return EINA_FALSE;
+ }
+ else curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, 0);
+ if (mode == MODE_POST)
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_POST, 1);
+ }
+
+ switch (url_con->time_condition)
+ {
+ case ECORE_CON_URL_TIME_NONE:
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
+ CURL_TIMECOND_NONE);
+ break;
+
+ case ECORE_CON_URL_TIME_IFMODSINCE:
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
+ CURL_TIMECOND_IFMODSINCE);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE,
+ (long)url_con->timestamp);
+ break;
+
+ case ECORE_CON_URL_TIME_IFUNMODSINCE:
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
+ CURL_TIMECOND_IFUNMODSINCE);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE,
+ (long)url_con->timestamp);
+ break;
+ }
+
+ /* Additional headers */
+ EINA_LIST_FOREACH(url_con->additional_headers, l, s)
+ url_con->headers = curl_slist_append(url_con->headers, s);
+
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPHEADER, url_con->headers);
+
+ url_con->received = 0;
+
+ return _ecore_con_url_perform(url_con);
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)mode;
+ (void)data;
+ (void)length;
+ (void)content_type;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_get(Ecore_Con_Url *url_con)
+{
+ return _ecore_con_url_send(url_con, MODE_GET, NULL, 0, NULL);
+}
+
+EAPI Eina_Bool
+ecore_con_url_post(Ecore_Con_Url *url_con, const void *data, long length, const char *content_type)
+{
+ return _ecore_con_url_send(url_con, MODE_POST, data, length, content_type);
+}
+
+EAPI Eina_Bool
+ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, const char *filename, const char *user, const char *pass, const char *upload_dir)
+{
+#ifdef HAVE_CURL
+ char url[4096];
+ char userpwd[4096];
+ FILE *fd;
+ struct stat file_info;
+ CURLcode ret;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con,
+ ECORE_MAGIC_CON_URL,
+ "ecore_con_url_ftp_upload");
+ return EINA_FALSE;
+ }
+
+ if (url_con->dead) return EINA_FALSE;
+ if (!url_con->url) return EINA_FALSE;
+ if ((!filename) || (!filename[0])) return EINA_FALSE;
+
+ if (stat(filename, &file_info))
+ return EINA_FALSE;
+
+ snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass);
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERPWD, userpwd);
+ if (ret != CURLE_OK)
+ {
+ ERR("Could not set username and password for FTP upload: %s",
+ curl_easy_strerror(ret));
+ return EINA_FALSE;
+ }
+
+ char tmp[PATH_MAX];
+ snprintf(tmp, PATH_MAX, "%s", filename);
+
+ if (upload_dir)
+ snprintf(url, sizeof(url), "ftp://%s/%s/%s", url_con->url,
+ upload_dir, basename(tmp));
+ else
+ snprintf(url, sizeof(url), "ftp://%s/%s", url_con->url,
+ basename(tmp));
+
+ if (!ecore_con_url_url_set(url_con, url))
+ return EINA_FALSE;
+
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_INFILESIZE_LARGE,
+ (curl_off_t)file_info.st_size);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_UPLOAD, 1);
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_READFUNCTION,
+ _ecore_con_url_read_cb);
+
+ fd = fopen(filename, "rb");
+ if (!fd)
+ {
+ ERR("Could not open \"%s\" for FTP upload", filename);
+ return EINA_FALSE;
+ }
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd);
+
+ return _ecore_con_url_perform(url_con);
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)filename;
+ (void)user;
+ (void)pass;
+ (void)upload_dir;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_init(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_init");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, "");
+#else
+ return;
+ (void)url_con;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, Eina_Bool ignore)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_ignore_old_session_set");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIESESSION, ignore);
+#else
+ return;
+ (void)url_con;
+ (void)ignore;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_clear(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_clear");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "ALL");
+#else
+ return;
+ (void)url_con;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_session_clear");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "SESS");
+#else
+ return;
+ (void)url_con;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, const char *const file_name)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_file_add");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, file_name);
+#else
+ return;
+ (void)url_con;
+ (void)file_name;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, const char *const cookiejar_file)
+{
+#ifdef HAVE_CURL
+ CURLcode ret;
+
+ if (!url_con)
+ return EINA_FALSE;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_jar_file_set");
+ return EINA_FALSE;
+ }
+
+ if (url_con->dead) return EINA_FALSE;
+ ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEJAR,
+ cookiejar_file);
+ if (ret != CURLE_OK)
+ {
+ ERR("Setting the cookie-jar name failed: %s",
+ curl_easy_strerror(ret));
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)cookiejar_file;
+#endif
+}
+
+EAPI void
+ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con)
+{
+#ifdef HAVE_CURL
+ if (!url_con)
+ return;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_cookies_jar_write");
+ return;
+ }
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "FLUSH");
+#else
+ return;
+ (void)url_con;
+#endif
+}
+
+EAPI void
+ecore_con_url_verbose_set(Ecore_Con_Url *url_con, Eina_Bool verbose)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_verbose_set");
+ return;
+ }
+
+ if (!url_con->url)
+ return;
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, (int)verbose);
+#else
+ return;
+ (void)url_con;
+ (void)verbose;
+#endif
+}
+
+EAPI void
+ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, Eina_Bool use_epsv)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_ftp_use_epsv_set");
+ return;
+ }
+
+ if (!url_con->url)
+ return;
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, (int)use_epsv);
+#else
+ return;
+ (void)url_con;
+ (void)use_epsv;
+#endif
+}
+
+/**
+ * Toggle libcurl's verify peer's certificate option.
+ *
+ * If @p verify is @c EINA_TRUE, libcurl will verify
+ * the authenticity of the peer's certificate, otherwise
+ * it will not. Default behavior of libcurl is to check
+ * peer's certificate.
+ *
+ * @param url_con Ecore_Con_Url instance which will be acted upon.
+ * @param verify Whether or not libcurl will check peer's certificate.
+ * @since 1.1.0
+ */
+EAPI void
+ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con, Eina_Bool verify)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
+ "ecore_con_url_ssl_verify_peer_set");
+ return;
+ }
+
+ if (!url_con->url)
+ return;
+
+ if (url_con->dead) return;
+ curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, (int)verify);
+#else
+ return;
+ (void)url_con;
+ (void)verify;
+#endif
+}
+
+/**
+ * Set a custom CA to trust for SSL/TLS connections.
+ *
+ * Specify the path of a file (in PEM format) containing one or more
+ * CA certificate(s) to use for the validation of the server certificate.
+ *
+ * This function can also disable CA validation if @p ca_path is @c NULL.
+ * However, the server certificate still needs to be valid for the connection
+ * to succeed (i.e., the certificate must concern the server the
+ * connection is made to).
+ *
+ * @param url_con Connection object that will use the custom CA.
+ * @param ca_path Path to a CA certificate(s) file or @c NULL to disable
+ * CA validation.
+ *
+ * @return @c 0 on success. When cURL is used, non-zero return values
+ * are equal to cURL error codes.
+ */
+EAPI int
+ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
+{
+ int res = -1;
+
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_ssl_ca_set");
+ return -1;
+ }
+
+ if (!url_con->url) return -1;
+ if (url_con->dead) return -1;
+ if (ca_path == NULL)
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0);
+ else
+ {
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 1);
+ if (!res)
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_CAINFO, ca_path);
+ }
+#else
+ return -1;
+ (void)url_con;
+ (void)ca_path;
+#endif
+
+ return res;
+}
+
+EAPI Eina_Bool
+ecore_con_url_http_version_set(Ecore_Con_Url *url_con, Ecore_Con_Url_Http_Version version)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_http_version_set");
+ return EINA_FALSE;
+ }
+ if (url_con->dead) return EINA_FALSE;
+ switch (version)
+ {
+ case ECORE_CON_URL_HTTP_VERSION_1_0:
+ res = curl_easy_setopt(url_con->curl_easy,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_0);
+ break;
+
+ case ECORE_CON_URL_HTTP_VERSION_1_1:
+ res = curl_easy_setopt(url_con->curl_easy,
+ CURLOPT_HTTP_VERSION,
+ CURL_HTTP_VERSION_1_1);
+ break;
+
+ default:
+ break;
+ }
+ if (res != CURLE_OK)
+ {
+ ERR("curl http version setting failed: %s", curl_easy_strerror(res));
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ (void)url_con;
+ (void)version;
+ return EINA_FALSE;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ curl_version_info_data *vers = NULL;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_set");
+ return EINA_FALSE;
+ }
+
+ if (!url_con->url) return EINA_FALSE;
+ if (url_con->dead) return EINA_FALSE;
+
+ if (!proxy) res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, "");
+ else
+ {
+ // before curl version 7.21.7, socks protocol:// prefix is not supported
+ // (e.g. socks4://, socks4a://, socks5:// or socks5h://, etc.)
+ vers = curl_version_info(CURLVERSION_NOW);
+ if (vers->version_num < 0x71507)
+ {
+ url_con->proxy_type = CURLPROXY_HTTP;
+ if (strstr(proxy, "socks4a"))
+ url_con->proxy_type = CURLPROXY_SOCKS4A;
+ else if (strstr(proxy, "socks4"))
+ url_con->proxy_type = CURLPROXY_SOCKS4;
+ else if (strstr(proxy, "socks5h"))
+ url_con->proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
+ else if (strstr(proxy, "socks5"))
+ url_con->proxy_type = CURLPROXY_SOCKS5;
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXYTYPE,
+ url_con->proxy_type);
+ if (res != CURLE_OK)
+ {
+ ERR("curl proxy type setting failed: %s",
+ curl_easy_strerror(res));
+ url_con->proxy_type = -1;
+ return EINA_FALSE;
+ }
+ }
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, proxy);
+ }
+ if (res != CURLE_OK)
+ {
+ ERR("curl proxy setting failed: %s", curl_easy_strerror(res));
+ url_con->proxy_type = -1;
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)proxy;
+#endif
+}
+
+EAPI void
+ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_timeout_set");
+ return;
+ }
+
+ if (url_con->dead) return;
+ if (!url_con->url || timeout < 0) return;
+ if (url_con->timer) ecore_timer_del(url_con->timer);
+ url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb, url_con);
+#else
+ return;
+ (void)url_con;
+ (void)timeout;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_username_set");
+ return EINA_FALSE;
+ }
+
+ if (url_con->dead) return EINA_FALSE;
+ if (!url_con->url) return EINA_FALSE;
+ if ((!username) || (!username[0])) return EINA_FALSE;
+ if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
+ {
+ ERR("Proxy type should be socks5 and above");
+ return EINA_FALSE;
+ }
+
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
+ if (res != CURLE_OK)
+ {
+ ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)username;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_password_set");
+ return EINA_FALSE;
+ }
+ if (!url_con->url) return EINA_FALSE;
+ if (url_con->dead) return EINA_FALSE;
+ if (!password) return EINA_FALSE;
+ if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
+ {
+ ERR("Proxy type should be socks5 and above");
+ return EINA_FALSE;
+ }
+
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
+ if (res != CURLE_OK)
+ {
+ ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)password;
+#endif
+}
+
+/**
+ * @}
+ */
+
+#ifdef HAVE_CURL
+static void
+_ecore_con_url_status_get(Ecore_Con_Url *url_con)
+{
+ long status = 0;
+
+ if (!url_con->curl_easy) return;
+ if (!curl_easy_getinfo(url_con->curl_easy, CURLINFO_RESPONSE_CODE, &status))
+ url_con->status = status;
+ else
+ url_con->status = 0;
+}
+
+static void
+_ecore_con_url_event_url_complete(Ecore_Con_Url *url_con, CURLMsg *curlmsg)
+{
+ Ecore_Con_Event_Url_Complete *e;
+ int status = url_con->status;
+
+ e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
+ if (!e) return;
+
+ if (!curlmsg)
+ {
+ ERR("Event completed without CURL message handle. Shouldn't happen");
+ }
+ else if ((curlmsg->msg == CURLMSG_DONE) &&
+ (curlmsg->data.result == CURLE_OPERATION_TIMEDOUT) &&
+ (!curlmsg->easy_handle))
+ {
+ /* easy_handle is set to NULL on timeout messages */
+ status = 408; /* Request Timeout */
+ }
+ else if (curlmsg->data.result == CURLE_OK)
+ {
+ if (!status)
+ {
+ _ecore_con_url_status_get(url_con);
+ status = url_con->status;
+ }
+ }
+ else
+ {
+ ERR("Curl message have errors: %d (%s)",
+ curlmsg->data.result, curl_easy_strerror(curlmsg->data.result));
+ }
+
+ e->status = status;
+ e->url_con = url_con;
+
+ url_con->event_count++;
+ ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con);
+}
+
+static void
+_ecore_con_url_multi_remove(Ecore_Con_Url *url_con)
+{
+ CURLMcode ret;
+
+ ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
+ url_con->multi = EINA_FALSE;
+ if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
+}
+
+static Eina_Bool
+_ecore_con_url_timeout_cb(void *data)
+{
+ Ecore_Con_Url *url_con = data;
+ CURLMsg timeout_msg;
+
+ if (!url_con) return ECORE_CALLBACK_CANCEL;
+ if (!url_con->curl_easy) return ECORE_CALLBACK_CANCEL;
+
+ _ecore_con_url_multi_remove(url_con);
+ _url_con_list = eina_list_remove(_url_con_list, url_con);
+
+ curl_slist_free_all(url_con->headers);
+ url_con->headers = NULL;
+
+ url_con->timer = NULL;
+
+ timeout_msg.msg = CURLMSG_DONE;
+ timeout_msg.easy_handle = NULL;
+ timeout_msg.data.result = CURLE_OPERATION_TIMEDOUT;
+
+ _ecore_con_url_event_url_complete(url_con, &timeout_msg);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static size_t
+_ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp)
+{
+ Ecore_Con_Url *url_con;
+ Ecore_Con_Event_Url_Data *e;
+ size_t real_size = size * nitems;
+
+ url_con = (Ecore_Con_Url *)userp;
+
+ if (!url_con)
+ return -1;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_cb");
+ return -1;
+ }
+
+ url_con->received += real_size;
+
+ INF("reading from %s", url_con->url);
+ if (url_con->write_fd < 0)
+ {
+ e =
+ malloc(sizeof(Ecore_Con_Event_Url_Data) + sizeof(unsigned char) *
+ (real_size - 1));
+ if (e)
+ {
+ e->url_con = url_con;
+ e->size = real_size;
+ memcpy(e->data, buffer, real_size);
+ url_con->event_count++;
+ ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con);
+ }
+ }
+ else
+ {
+ ssize_t count = 0;
+ size_t total_size = real_size;
+ size_t offset = 0;
+
+ while (total_size > 0)
+ {
+ count = write(url_con->write_fd,
+ (char *)buffer + offset,
+ total_size);
+ if (count < 0)
+ {
+ if (errno != EAGAIN && errno != EINTR)
+ return -1;
+ }
+ else
+ {
+ total_size -= count;
+ offset += count;
+ }
+ }
+ }
+
+ return real_size;
+}
+
+static size_t
+_ecore_con_url_header_cb(void *ptr, size_t size, size_t nitems, void *stream)
+{
+ size_t real_size = size * nitems;
+ Ecore_Con_Url *url_con = stream;
+
+ char *header = malloc(sizeof(char) * (real_size + 1));
+ if (!header)
+ return real_size;
+
+ memcpy(header, ptr, real_size);
+ header[real_size] = '\0';
+
+ url_con->response_headers = eina_list_append(url_con->response_headers,
+ header);
+
+ return real_size;
+}
+
+static int
+_ecore_con_url_progress_cb(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
+{
+ Ecore_Con_Event_Url_Progress *e;
+ Ecore_Con_Url *url_con;
+
+ url_con = clientp;
+
+ e = malloc(sizeof(Ecore_Con_Event_Url_Progress));
+ if (e)
+ {
+ e->url_con = url_con;
+ e->down.total = dltotal;
+ e->down.now = dlnow;
+ e->up.total = ultotal;
+ e->up.now = ulnow;
+ url_con->event_count++;
+ ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con);
+ }
+
+ return 0;
+}
+
+static size_t
+_ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, void *stream)
+{
+ size_t retcode = fread(ptr, size, nitems, stream);
+
+ if (ferror((FILE *)stream))
+ {
+ fclose(stream);
+ return CURL_READFUNC_ABORT;
+ }
+ else if (retcode == 0)
+ {
+ fclose((FILE *)stream);
+ return 0;
+ }
+
+#ifdef _WIN32
+ INF("*** We read %Iu bytes from file", retcode);
+#else
+ INF("*** We read %zu bytes from file", retcode);
+#endif
+ return retcode;
+}
+
+static void
+_ecore_con_url_info_read(void)
+{
+ CURLMsg *curlmsg;
+ int n_remaining;
+
+ while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
+ {
+ Eina_List *l, *ll;
+ Ecore_Con_Url *url_con = NULL;
+ DBG("Curl message: %d", curlmsg->msg);
+
+ if (curlmsg->msg == CURLMSG_DONE)
+ {
+ EINA_LIST_FOREACH_SAFE(_url_con_list, l, ll, url_con)
+ {
+ if (curlmsg->easy_handle == url_con->curl_easy)
+ _ecore_con_url_event_url_complete(url_con, curlmsg);
+ }
+ }
+ }
+}
+
+static void
+_ecore_con_url_curl_clear(void)
+{
+ Ecore_Fd_Handler *fdh;
+ Ecore_Con_Url *url_con;
+
+ EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh);
+ EINA_LIST_FREE(_url_con_list, url_con) _ecore_con_url_multi_remove(url_con);
+}
+
+static Eina_Bool
+_ecore_con_url_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Ecore_Fd_Handler *fdh;
+ long ms;
+
+ EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh);
+
+ curl_multi_timeout(_curlm, &ms);
+ if ((ms >= CURL_MIN_TIMEOUT) || (ms <= 0)) ms = CURL_MIN_TIMEOUT;
+ ecore_timer_interval_set(_curl_timer, (double)ms / 1000.0);
+
+ if (!_curl_idler)
+ _curl_idler = ecore_idler_add(_ecore_con_url_timer, NULL);
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_con_url_fdset(void)
+{
+ CURLMcode ret;
+ fd_set read_set, write_set, exc_set;
+ int fd, fd_max;
+
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+ FD_ZERO(&exc_set);
+
+ ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, &fd_max);
+ if (ret != CURLM_OK)
+ {
+ ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
+ return;
+ }
+
+ for (fd = 0; fd <= fd_max; fd++)
+ {
+ int flags = 0;
+ if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ;
+ if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE;
+ if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR;
+ if (flags)
+ {
+ // FIXME: Who is owner (easy_handle) of this fd?? (Curl do not give this info.)
+ // This cause "Failed to delete epoll fd xx!" error messages
+ Ecore_Fd_Handler *fd_handler;
+ fd_handler = ecore_main_fd_handler_add(fd, flags,
+ _ecore_con_url_fd_handler,
+ NULL, NULL, NULL);
+ if (fd_handler)
+ _fd_hd_list = eina_list_append(_fd_hd_list, fd_handler);
+ }
+ }
+}
+
+static Eina_Bool
+_ecore_con_url_timer(void *data EINA_UNUSED)
+{
+ Ecore_Fd_Handler *fdh;
+ int still_running;
+ CURLMcode ret;
+
+ EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh);
+ _ecore_con_url_info_read();
+
+ ret = curl_multi_perform(_curlm, &still_running);
+ if (ret == CURLM_CALL_MULTI_PERFORM)
+ {
+ DBG("curl_multi_perform() again immediately");
+ return ECORE_CALLBACK_RENEW;
+ }
+ else if (ret != CURLM_OK)
+ {
+ ERR("curl_multi_perform() failed: %s", curl_multi_strerror(ret));
+ _ecore_con_url_curl_clear();
+ ecore_timer_freeze(_curl_timer);
+ if (_curl_idler)
+ {
+ ecore_idler_del(_curl_idler);
+ _curl_idler = NULL;
+ }
+ }
+
+ if (still_running)
+ {
+ long ms;
+ _ecore_con_url_fdset();
+ curl_multi_timeout(_curlm, &ms);
+ DBG("multiperform is still running: %d, timeout: %ld", still_running, ms);
+ if ((ms >= CURL_MIN_TIMEOUT) || (ms <= 0)) ms = CURL_MIN_TIMEOUT;
+ ecore_timer_interval_set(_curl_timer, (double)ms / 1000.0);
+ }
+ else
+ {
+ DBG("multiperform ended");
+ _ecore_con_url_info_read();
+ _ecore_con_url_curl_clear();
+ ecore_timer_freeze(_curl_timer);
+ if (_curl_idler)
+ {
+ ecore_idler_del(_curl_idler);
+ _curl_idler = NULL;
+ }
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_con_url_perform(Ecore_Con_Url *url_con)
+{
+ CURLMcode ret;
+
+ ret = curl_multi_add_handle(_curlm, url_con->curl_easy);
+ if (ret != CURLM_OK)
+ {
+ ERR("curl_multi_add_handle() failed: %s", curl_multi_strerror(ret));
+ return EINA_FALSE;
+ }
+
+ url_con->multi = EINA_TRUE;
+ _url_con_list = eina_list_append(_url_con_list, url_con);
+ ecore_timer_thaw(_curl_timer);
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_con_event_url_free(Ecore_Con_Url *url_con, void *ev)
+{
+ free(ev);
+ url_con->event_count--;
+ if (url_con->dead && (!url_con->event_count))
+ ecore_con_url_free(url_con);
+}
+
+#endif
diff --git a/src/lib/ecore_directfb/Ecore_DirectFB.h b/src/lib/ecore_directfb/Ecore_DirectFB.h
new file mode 100644
index 0000000000..3b94816d96
--- /dev/null
+++ b/src/lib/ecore_directfb/Ecore_DirectFB.h
@@ -0,0 +1,181 @@
+#ifndef _ECORE_DIRECTFB_H
+#define _ECORE_DIRECTFB_H
+
+#include <Eina.h>
+
+#include <directfb.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif /* ifdef EAPI */
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else /* if __GNUC__ >= 4 */
+# define EAPI
+# endif /* if __GNUC__ >= 4 */
+#else /* ifdef __GNUC__ */
+# define EAPI
+#endif /* ifdef __GNUC__ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* ifdef __cplusplus */
+
+EAPI extern int ECORE_DIRECTFB_EVENT_POSITION;
+EAPI extern int ECORE_DIRECTFB_EVENT_SIZE;
+EAPI extern int ECORE_DIRECTFB_EVENT_CLOSE;
+EAPI extern int ECORE_DIRECTFB_EVENT_DESTROYED;
+EAPI extern int ECORE_DIRECTFB_EVENT_GOT_FOCUS;
+EAPI extern int ECORE_DIRECTFB_EVENT_LOST_FOCUS;
+EAPI extern int ECORE_DIRECTFB_EVENT_KEY_DOWN;
+EAPI extern int ECORE_DIRECTFB_EVENT_KEY_UP;
+EAPI extern int ECORE_DIRECTFB_EVENT_BUTTON_DOWN;
+EAPI extern int ECORE_DIRECTFB_EVENT_BUTTON_UP;
+EAPI extern int ECORE_DIRECTFB_EVENT_MOTION;
+EAPI extern int ECORE_DIRECTFB_EVENT_ENTER;
+EAPI extern int ECORE_DIRECTFB_EVENT_LEAVE;
+EAPI extern int ECORE_DIRECTFB_EVENT_WHEEL;
+
+#ifndef _ECORE_DIRECTFB_WINDOW_PREDEF
+typedef struct _Ecore_DirectFB_Window Ecore_DirectFB_Window;
+#endif /* ifndef _ECORE_DIRECTFB_WINDOW_PREDEF */
+typedef struct _Ecore_DirectFB_Cursor Ecore_DirectFB_Cursor;
+
+typedef struct _Ecore_DirectFB_Event_Key_Down Ecore_DirectFB_Event_Key_Down;
+typedef struct _Ecore_DirectFB_Event_Key_Up Ecore_DirectFB_Event_Key_Up;
+typedef struct _Ecore_DirectFB_Event_Button_Down Ecore_DirectFB_Event_Button_Down;
+typedef struct _Ecore_DirectFB_Event_Button_Up Ecore_DirectFB_Event_Button_Up;
+typedef struct _Ecore_DirectFB_Event_Motion Ecore_DirectFB_Event_Motion;
+typedef struct _Ecore_DirectFB_Event_Enter Ecore_DirectFB_Event_Enter;
+typedef struct _Ecore_DirectFB_Event_Leave Ecore_DirectFB_Event_Leave;
+typedef struct _Ecore_DirectFB_Event_Wheel Ecore_DirectFB_Event_Wheel;
+typedef struct _Ecore_DirectFB_Event_Got_Focus Ecore_DirectFB_Event_Got_Focus;
+typedef struct _Ecore_DirectFB_Event_Lost_Focus Ecore_DirectFB_Event_Lost_Focus;
+
+/* this struct is to keep windows data (id, window itself and surface) in memory as every call
+ * to DirectFB for this values (e.g window->GetSurface(window,&surface)) will increment the
+ * reference count, then we will have to release N times the data, so better we just ask for
+ them once */
+struct _Ecore_DirectFB_Window
+{
+ DFBWindowID id;
+ IDirectFBWindow *window;
+ IDirectFBSurface *surface;
+ Ecore_DirectFB_Cursor *cursor;
+};
+
+struct _Ecore_DirectFB_Cursor
+{
+ IDirectFBSurface *surface;
+ int hot_x;
+ int hot_y;
+};
+
+struct _Ecore_DirectFB_Event_Key_Down /** DirectFB Key Down event */
+{
+ char *name; /**< The name of the key that was released */
+ char *string; /**< The logical symbol of the key that was pressed */
+ char *key_compose; /**< The UTF-8 string conversion if any */
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Key_Up /** DirectFB Key Up event */
+{
+ char *name; /**< The name of the key that was released */
+ char *string; /**< The logical symbol of the key that was pressed */
+ char *key_compose; /**< The UTF-8 string conversion if any */
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Button_Down
+{
+ int button;
+ int modifiers;
+ int x, y;
+ unsigned int time;
+ int double_click : 1;
+ int triple_click : 1;
+ DFBWindowID win;
+};
+struct _Ecore_DirectFB_Event_Button_Up
+{
+ int button;
+ int modifiers;
+ int x, y;
+ unsigned int time;
+ DFBWindowID win;
+ int double_click : 1;
+ int triple_click : 1;
+};
+struct _Ecore_DirectFB_Event_Motion
+{
+ int modifiers;
+ int x, y;
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Enter
+{
+ int modifiers;
+ int x, y;
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Leave
+{
+ int modifiers;
+ int x, y;
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Wheel
+{
+ int direction;
+ int z;
+ int modifiers;
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Got_Focus
+{
+ unsigned int time;
+ DFBWindowID win;
+};
+
+struct _Ecore_DirectFB_Event_Lost_Focus
+{
+ unsigned int time;
+ DFBWindowID win;
+};
+
+/* main functions */
+EAPI int ecore_directfb_init(const char *name);
+EAPI int ecore_directfb_shutdown(void);
+EAPI IDirectFB * ecore_directfb_interface_get(void);
+
+/* window operations */
+EAPI Ecore_DirectFB_Window *ecore_directfb_window_new(int x, int y, int w, int h);
+EAPI void ecore_directfb_window_free(Ecore_DirectFB_Window *window);
+EAPI void ecore_directfb_window_move(Ecore_DirectFB_Window *window, int x, int y);
+EAPI void ecore_directfb_window_resize(Ecore_DirectFB_Window *window, int w, int h);
+EAPI void ecore_directfb_window_focus(Ecore_DirectFB_Window *window);
+EAPI void ecore_directfb_window_show(Ecore_DirectFB_Window *window);
+EAPI void ecore_directfb_window_hide(Ecore_DirectFB_Window *window);
+EAPI void ecore_directfb_window_shaped_set(Ecore_DirectFB_Window *window, Eina_Bool set);
+EAPI void ecore_directfb_window_fullscreen_set(Ecore_DirectFB_Window *window, Eina_Bool set);
+EAPI void ecore_directfb_window_size_get(Ecore_DirectFB_Window *window, int *w, int *h);
+EAPI void ecore_directfb_window_cursor_show(Ecore_DirectFB_Window *window, Eina_Bool show);
+
+#ifdef __cplusplus
+}
+#endif /* ifdef __cplusplus */
+
+#endif /* ifndef _ECORE_DIRECTFB_H */
diff --git a/src/lib/ecore_directfb/ecore_directfb.c b/src/lib/ecore_directfb/ecore_directfb.c
new file mode 100644
index 0000000000..008fa1d6f9
--- /dev/null
+++ b/src/lib/ecore_directfb/ecore_directfb.c
@@ -0,0 +1,758 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "Ecore_DirectFB.h"
+#include "ecore_directfb_private.h"
+#include "ecore_directfb_keys.h"
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* ecore_directfb */
+/******************/
+/* About */
+/* with this you can create windows of directfb and handle events through ecore
+ * TODO:
+ * - handle all event types
+ * -
+ * */
+int _ecore_directfb_log_dom = -1;
+
+static int _ecore_directfb_init_count = 0;
+
+static int _window_event_fd = 0;
+static int _input_event_fd = 0;
+
+static int _ecore_directfb_fullscreen_window_id = 0;
+static int _cursor_x = 0;
+static int _cursor_y = 0;
+
+EAPI int ECORE_DIRECTFB_EVENT_POSITION = 0;
+EAPI int ECORE_DIRECTFB_EVENT_SIZE = 0;
+EAPI int ECORE_DIRECTFB_EVENT_CLOSE = 0;
+EAPI int ECORE_DIRECTFB_EVENT_DESTROYED = 0;
+EAPI int ECORE_DIRECTFB_EVENT_GOT_FOCUS = 0;
+EAPI int ECORE_DIRECTFB_EVENT_LOST_FOCUS = 0;
+EAPI int ECORE_DIRECTFB_EVENT_KEY_DOWN = 0;
+EAPI int ECORE_DIRECTFB_EVENT_KEY_UP = 0;
+EAPI int ECORE_DIRECTFB_EVENT_BUTTON_DOWN = 0;
+EAPI int ECORE_DIRECTFB_EVENT_BUTTON_UP = 0;
+EAPI int ECORE_DIRECTFB_EVENT_MOTION = 0;
+EAPI int ECORE_DIRECTFB_EVENT_ENTER = 0;
+EAPI int ECORE_DIRECTFB_EVENT_LEAVE = 0;
+EAPI int ECORE_DIRECTFB_EVENT_WHEEL = 0;
+
+static Ecore_Fd_Handler *_window_event_fd_handler_handle = NULL;
+static Ecore_Fd_Handler *_input_event_fd_handler_handle = NULL;
+
+/* this hash is to store all the possible key names for fast lookup */
+static Eina_Hash *_ecore_directfb_key_symbols_hash = NULL;
+
+static IDirectFB *_dfb = NULL; // the main interface
+static IDirectFBEventBuffer *_window_event; // the main event buffer (all windows are attached to this)
+static IDirectFBEventBuffer *_input_event; // the main event buffer (all windows are attached to this)
+static IDirectFBDisplayLayer *_layer; // the main layer
+static DFBResult _err; // useful for DFBCHECK
+
+/*******************/
+/* local functions */
+/*******************/
+
+/* free ecore directfb events functions */
+/****************************************/
+
+static void
+_ecore_directfb_event_free_key_down(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_DirectFB_Event_Key_Down *e;
+
+ e = ev;
+ if(e->name)
+ free(e->name);
+
+ if (e->string)
+ free(e->string);
+
+ if (e->key_compose)
+ free(e->key_compose);
+
+ free(e);
+}
+
+static void
+_ecore_directfb_event_free_key_up(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_DirectFB_Event_Key_Up *e;
+
+ e = ev;
+ if(e->name)
+ free(e->name);
+
+ if (e->string)
+ free(e->string);
+
+ if (e->key_compose)
+ free(e->key_compose);
+
+ free(e);
+}
+
+/* directfb window input events handler */
+/****************************************/
+
+static void
+_ecore_directfb_event_handle_motion(DFBEvent *evt)
+{
+ Ecore_DirectFB_Event_Motion *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Motion));
+
+ switch(evt->clazz)
+ {
+ case DFEC_INPUT:
+ e->modifiers = 0;
+ switch(evt->input.axis)
+ {
+ case DIAI_X:
+ e->x = _cursor_x = evt->input.axisabs;
+ e->y = _cursor_y;
+ break;
+
+ case DIAI_Y:
+ e->y = _cursor_y = evt->input.axisabs;
+ e->x = _cursor_x;
+ break;
+
+ case DIAI_Z:
+ //_ecore_directfb_event_handle_wheel(evt);
+ return;
+
+ default:
+ return;
+ }
+ e->win = _ecore_directfb_fullscreen_window_id;
+ e->time = 0;
+ break;
+
+ case DFEC_WINDOW:
+ e->modifiers = 0;
+ e->x = evt->window.x;
+ e->y = evt->window.y;
+ e->win = evt->window.window_id;
+ e->time = 0;
+ break;
+
+ default:
+ break;
+ }
+ ecore_event_add(ECORE_DIRECTFB_EVENT_MOTION, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_key_down(DFBEvent *evt)
+{
+ Ecore_DirectFB_Event_Key_Down *e;
+ unsigned int key_symbol;
+ struct keymap *k;
+
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Key_Down));
+
+ switch(evt->clazz)
+ {
+ case DFEC_INPUT:
+ key_symbol = evt->input.key_symbol;
+ k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol);
+
+ if(!k)
+ {
+ ERR("Symbol %0X of class DFEC_INPUT not found.", evt->input.key_symbol);
+ return;
+ }
+
+ e->name = strdup(k->name);
+ e->string = strdup(k->string);
+ e->key_compose = NULL;
+ e->win = _ecore_directfb_fullscreen_window_id;
+ e->time = 0;
+ break;
+
+ case DFEC_WINDOW:
+ key_symbol = evt->window.key_symbol;
+ k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol);
+
+ if(!k)
+ {
+ ERR("Symbol %0X of class DFEC_WINDOW not found.", evt->window.key_symbol);
+ return;
+ }
+
+ e->name = strdup(k->name);
+ e->string = strdup(k->string);
+ e->key_compose = NULL;
+ e->win = evt->window.window_id;
+ e->time = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_KEY_DOWN, e, _ecore_directfb_event_free_key_down, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_key_up(DFBEvent *evt)
+{
+ Ecore_DirectFB_Event_Key_Up *e;
+ unsigned int key_symbol;
+ struct keymap *k;
+
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Key_Up));
+
+ switch(evt->clazz)
+ {
+ case DFEC_INPUT:
+ key_symbol = evt->input.key_symbol;
+ k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol);
+
+ if(!k)
+ {
+ ERR("Symbol %0X of class DFEC_INPUT not found.", evt->input.key_symbol);
+ return;
+ }
+
+ e->name = strdup(k->name);
+ e->string = strdup(k->string);
+ e->key_compose = NULL;
+ e->win = _ecore_directfb_fullscreen_window_id;
+ e->time = 0;
+ break;
+
+ case DFEC_WINDOW:
+ key_symbol = evt->window.key_symbol;
+ k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol);
+
+ if(!k)
+ {
+ ERR("Symbol %0X of class DFEC_WINDOW not found.", evt->window.key_symbol);
+ return;
+ }
+
+ e->name = strdup(k->name);
+ e->string = strdup(k->string);
+ e->key_compose = NULL;
+ e->win = evt->window.window_id;
+ e->time = 0;
+ break;
+
+ default:
+ break;
+ }
+ ecore_event_add(ECORE_DIRECTFB_EVENT_KEY_UP, e, _ecore_directfb_event_free_key_up, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_button_down(DFBEvent *evt)
+{
+ Ecore_DirectFB_Event_Button_Down *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Button_Down));
+
+ switch(evt->clazz)
+ {
+ case DFEC_INPUT:
+ e->button = evt->input.button + 1;
+ e->modifiers = 0;
+ DFBCHECK(_layer->GetCursorPosition(_layer,&e->x,&e->y));
+ e->x = _cursor_x;
+ e->y = _cursor_y;
+ e->win = _ecore_directfb_fullscreen_window_id;
+ e->time = 0;
+
+ break;
+
+ case DFEC_WINDOW:
+ e->button = evt->window.button + 1;
+ e->modifiers = 0;
+ e->x = evt->window.x;
+ e->y = evt->window.y;
+ e->win = evt->window.window_id;
+ e->time = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_BUTTON_DOWN, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_button_up(DFBEvent *evt)
+{
+ Ecore_DirectFB_Event_Button_Up *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Button_Up));
+
+ switch(evt->clazz)
+ {
+ case DFEC_INPUT:
+ e->button = evt->input.button + 1;
+ e->modifiers = 0;
+ e->x = _cursor_x;
+ e->y = _cursor_y;
+ e->win = _ecore_directfb_fullscreen_window_id;
+ e->time = 0;
+
+ break;
+
+ case DFEC_WINDOW:
+ e->button = evt->window.button + 1;
+ e->modifiers = 0;
+ e->x = evt->window.x;
+ e->y = evt->window.y;
+ e->win = evt->window.window_id;
+ e->time = 0;
+ break;
+
+ default:
+ break;
+ }
+ ecore_event_add(ECORE_DIRECTFB_EVENT_BUTTON_UP, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_enter(DFBWindowEvent *evt)
+{
+ Ecore_DirectFB_Event_Enter *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Enter));
+
+ e->modifiers = 0;
+ e->x = evt->x;
+ e->y = evt->y;
+ e->win = evt->window_id;
+ e->time = 0;
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_ENTER, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_leave(DFBWindowEvent *evt)
+{
+ Ecore_DirectFB_Event_Leave *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Leave));
+
+ e->modifiers = 0;
+ e->x = evt->x;
+ e->y = evt->y;
+ e->win = evt->window_id;
+ e->time = 0;
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_LEAVE, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_wheel(DFBWindowEvent *evt)
+{
+ Ecore_DirectFB_Event_Wheel *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Wheel));
+
+ // currently there's no direction (only up/down);
+ e->direction = 0;
+ e->z = evt->step;
+ e->modifiers = 0;
+ e->win = evt->window_id;
+ e->time = 0;
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_WHEEL, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_got_focus(DFBWindowEvent *evt)
+{
+ Ecore_DirectFB_Event_Got_Focus *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Got_Focus));
+
+ e->win = evt->window_id;
+ e->time = 0;
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_GOT_FOCUS, e, NULL, NULL);
+}
+
+static void
+_ecore_directfb_event_handle_lost_focus(DFBWindowEvent *evt)
+{
+ Ecore_DirectFB_Event_Lost_Focus *e;
+ e = calloc(1, sizeof(Ecore_DirectFB_Event_Lost_Focus));
+
+ e->win = evt->window_id;
+ e->time = 0;
+
+ ecore_event_add(ECORE_DIRECTFB_EVENT_LOST_FOCUS, e, NULL, NULL);
+}
+
+/* inputs and windows fds handlers */
+/***********************************/
+/* TODO fix this to handle windows and input events (fullscreen/window mode)
+ * in fullscreen theres no window_id so get the id from a global var (only one fullscreen
+ * window at a time */
+
+static Eina_Bool
+_ecore_directfb_input_event_fd_handler(void *data EINA_UNUSED,Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ DFBEvent evt;
+ int v = 0;
+
+ v = read(_input_event_fd, &evt, sizeof(DFBEvent));
+ if (v < 0)
+ return EINA_TRUE;
+
+ if (v < 1)
+ return EINA_TRUE;
+
+ /* we are getting duplicate events, only parse if we are in fullscreen */
+ //if(_ecore_directfb_fullscreen_window_id == 0) break;
+ if(evt.input.type == DIET_KEYPRESS)
+ _ecore_directfb_event_handle_key_down(&evt);
+
+ if(evt.input.type == DIET_KEYRELEASE)
+ _ecore_directfb_event_handle_key_up(&evt);
+
+ if(evt.input.type == DIET_BUTTONPRESS)
+ _ecore_directfb_event_handle_button_down(&evt);
+
+ if(evt.input.type == DIET_BUTTONRELEASE)
+ _ecore_directfb_event_handle_button_up(&evt);
+
+ if(evt.input.type == DIET_AXISMOTION)
+ _ecore_directfb_event_handle_motion(&evt);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_directfb_window_event_fd_handler(void *data EINA_UNUSED,Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ DFBEvent evt;
+ int v = 0;
+
+ v = read(_window_event_fd, &evt, sizeof(DFBEvent));
+ if (v < 0)
+ return EINA_TRUE;
+
+ if (v < 1)
+ return EINA_TRUE;
+
+ if(evt.window.type & DWET_POSITION)
+ INF("position");
+
+ if(evt.window.type & DWET_SIZE)
+ INF("size");
+
+ if(evt.window.type & DWET_CLOSE)
+ INF("close");
+
+ if(evt.window.type & DWET_DESTROYED)
+ INF("destroyed");
+
+ if(evt.window.type & DWET_GOTFOCUS)
+ _ecore_directfb_event_handle_got_focus(&evt.window);
+
+ if(evt.window.type & DWET_LOSTFOCUS)
+ _ecore_directfb_event_handle_lost_focus(&evt.window);
+
+ if(evt.window.type & DWET_KEYDOWN)
+ _ecore_directfb_event_handle_key_down(&evt);
+
+ if(evt.window.type & DWET_KEYUP)
+ _ecore_directfb_event_handle_key_up(&evt);
+
+ if(evt.window.type & DWET_BUTTONDOWN)
+ _ecore_directfb_event_handle_button_down(&evt);
+
+ if(evt.window.type & DWET_BUTTONUP)
+ _ecore_directfb_event_handle_button_up(&evt);
+
+ if(evt.window.type & DWET_MOTION)
+ _ecore_directfb_event_handle_motion(&evt);
+
+ if(evt.window.type & DWET_ENTER)
+ _ecore_directfb_event_handle_enter(&evt.window);
+
+ if(evt.window.type & DWET_LEAVE)
+ _ecore_directfb_event_handle_leave(&evt.window);
+
+ if(evt.window.type & DWET_WHEEL)
+ _ecore_directfb_event_handle_wheel(&evt.window);
+
+ return EINA_TRUE;
+}
+
+/* api functions */
+/*****************/
+
+EAPI IDirectFB *
+ecore_directfb_interface_get(void)
+{
+ return _dfb;
+}
+
+EAPI Ecore_DirectFB_Window *
+ecore_directfb_window_new(int x, int y, int w, int h)
+{
+ Ecore_DirectFB_Window *window;
+ IDirectFBWindow *dfb_window;
+ IDirectFBSurface *dfb_surface = NULL;
+ DFBWindowDescription desc;
+ DFBWindowID id;
+
+ memset(&desc, 0, sizeof(DFBWindowDescription));
+ desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS);
+ desc.posx = x;
+ desc.posy = y;
+ desc.width = w;
+ desc.height = h;
+ desc.caps = DWCAPS_ALPHACHANNEL;
+
+ DFBCHECK(_layer->CreateWindow(_layer, &desc, &dfb_window));
+
+ dfb_window->AttachEventBuffer(dfb_window, _window_event);
+ dfb_window->SetOptions(dfb_window,DWOP_NONE);
+ dfb_window->SetOpacity(dfb_window, 0xFF);
+
+ DFBCHECK(dfb_window->GetID(dfb_window, &id));
+ DFBCHECK(dfb_window->GetSurface(dfb_window,&dfb_surface));
+
+ window = malloc(sizeof(Ecore_DirectFB_Window));
+ window->id = id;
+ window->window = dfb_window;
+ window->surface = dfb_surface;
+ window->cursor = NULL;
+
+ return window;
+}
+
+EAPI void
+ecore_directfb_window_free(Ecore_DirectFB_Window *ecore_window)
+{
+ DFBCHECK(ecore_window->surface->Release(ecore_window->surface));
+ DFBCHECK(ecore_window->window->Release(ecore_window->window));
+ free(ecore_window);
+}
+
+EAPI void
+ecore_directfb_window_move(Ecore_DirectFB_Window *ecore_window, int x, int y)
+{
+ DFBCHECK(ecore_window->window->MoveTo(ecore_window->window, x, y));
+}
+
+EAPI void
+ecore_directfb_window_resize(Ecore_DirectFB_Window *ecore_window, int w, int h)
+{
+ DFBCHECK(ecore_window->window->Resize(ecore_window->window, w, h));
+}
+
+EAPI void
+ecore_directfb_window_focus(Ecore_DirectFB_Window *ecore_window)
+{
+ DFBCHECK(ecore_window->window->RequestFocus(ecore_window->window));
+}
+
+EAPI void
+ecore_directfb_window_hide(Ecore_DirectFB_Window *ecore_window)
+{
+ DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window, 0));
+}
+
+EAPI void
+ecore_directfb_window_show(Ecore_DirectFB_Window *ecore_window)
+{
+ DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window, 0xFF));
+}
+
+EAPI void
+ecore_directfb_window_shaped_set(Ecore_DirectFB_Window *ecore_window, Eina_Bool set)
+{
+ DFBWindowOptions opts;
+
+ DFBCHECK(ecore_window->window->GetOptions(ecore_window->window, &opts));
+ if(set)
+ {
+ opts |= DWOP_SHAPED;
+ opts |= DWOP_ALPHACHANNEL;
+ DFBCHECK(ecore_window->window->SetOptions(ecore_window->window, opts));
+ }
+ else
+ {
+ opts &= ~DWOP_SHAPED;
+ opts &= ~DWOP_ALPHACHANNEL;
+ DFBCHECK(ecore_window->window->SetOptions(ecore_window->window, opts));
+ }
+}
+
+EAPI void
+ecore_directfb_window_cursor_show(Ecore_DirectFB_Window *ecore_window, Eina_Bool show)
+{
+ if(!show)
+ {
+ /* create an empty cursor and set it */
+ IDirectFBSurface *cursor;
+ DFBSurfaceDescription desc;
+
+ memset(&desc, 0, sizeof(DFBSurfaceDescription));
+ desc.flags = (DSDESC_HEIGHT | DSDESC_WIDTH | DSDESC_PIXELFORMAT);
+ desc.width = 1;
+ desc.height = 1;
+ desc.pixelformat = DSPF_A1;
+
+ DFBCHECK(_dfb->CreateSurface(_dfb,&desc,&cursor));
+ DFBCHECK(cursor->Clear(cursor,0,0,0,0));
+ DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, cursor, 0, 0));
+ }
+ else
+ {
+ /* we already have a cursor surface so set it*/
+ if(ecore_window->cursor)
+ {
+ DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, ecore_window->cursor->surface, ecore_window->cursor->hot_x, ecore_window->cursor->hot_y));
+ }
+ /* or just set the default directfb cursor */
+ else
+ {
+ DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, NULL, 0, 0));
+ }
+ }
+}
+
+EAPI void
+ecore_directfb_window_cursor_set(Ecore_DirectFB_Window *ecore_window, Ecore_DirectFB_Cursor *cursor)
+{
+ if((!cursor) && (ecore_window->cursor))
+ {
+ ecore_window->cursor = NULL;
+ DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, NULL, 0, 0));
+ return;
+ }
+
+ if(cursor)
+ {
+ ecore_window->cursor = cursor;
+ DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, cursor->surface, cursor->hot_x, cursor->hot_y));
+ }
+}
+
+EAPI void
+ecore_directfb_window_fullscreen_set(Ecore_DirectFB_Window *ecore_window, Eina_Bool on)
+{
+ // always release the surface (we are going to get a new one in both cases)
+ DFBCHECK(ecore_window->surface->Release(ecore_window->surface));
+ if(on)
+ {
+ DFBCHECK(_layer->SetCooperativeLevel(_layer,DLSCL_EXCLUSIVE));
+ DFBCHECK(_layer->GetSurface(_layer,&ecore_window->surface));
+ DFBCHECK(_dfb->CreateInputEventBuffer(_dfb, DICAPS_ALL, DFB_FALSE, &_input_event));
+ DFBCHECK(_input_event->CreateFileDescriptor(_input_event,&_input_event_fd));
+ /* the event of axismove sends one axis at a time, so we must store both */
+ DFBCHECK(_layer->GetCursorPosition(_layer,&_cursor_x,&_cursor_y));
+
+ _input_event_fd_handler_handle = ecore_main_fd_handler_add(_input_event_fd,ECORE_FD_READ,_ecore_directfb_input_event_fd_handler, NULL,NULL,NULL);
+ _ecore_directfb_fullscreen_window_id = ecore_window->id;
+ }
+ else
+ {
+ ecore_main_fd_handler_del(_input_event_fd_handler_handle);
+ DFBCHECK(_input_event->Release(_input_event));
+ DFBCHECK(_layer->SetCooperativeLevel(_layer,DLSCL_SHARED));
+ DFBCHECK(ecore_window->window->GetSurface(ecore_window->window, &ecore_window->surface));
+ _ecore_directfb_fullscreen_window_id = 0;
+ }
+}
+
+EAPI void
+ecore_directfb_window_size_get(Ecore_DirectFB_Window *ecore_window, int *w, int *h)
+{
+ DFBCHECK(ecore_window->surface->GetSize(ecore_window->surface,w,h));
+ return;
+}
+
+EAPI int
+ecore_directfb_init(const char *name EINA_UNUSED)
+{
+ int i = 0;
+
+ if (++_ecore_directfb_init_count != 1)
+ return _ecore_directfb_init_count;
+
+ _ecore_directfb_log_dom = eina_log_domain_register
+ ("ecore_directfb", ECORE_DIRECTFB_DEFAULT_LOG_COLOR);
+ if(_ecore_directfb_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the Ecore directFB module.");
+ return _ecore_directfb_init_count--;
+ }
+
+ DFBCHECK(DirectFBInit(NULL,NULL));
+ DFBCHECK(DirectFBCreate(&_dfb));
+
+ DFBCHECK(_dfb->GetDisplayLayer(_dfb, DLID_PRIMARY, &_layer));
+ DFBCHECK(_layer->SetCooperativeLevel(_layer, DLSCL_SHARED));
+
+ /* window events and fd */
+ DFBCHECK(_dfb->CreateEventBuffer(_dfb, &_window_event));
+ DFBCHECK(_window_event->CreateFileDescriptor(_window_event,&_window_event_fd));
+ _window_event_fd_handler_handle = ecore_main_fd_handler_add(_window_event_fd,ECORE_FD_READ,_ecore_directfb_window_event_fd_handler, NULL,NULL,NULL);
+
+ /* register ecore directfb events */
+ ECORE_DIRECTFB_EVENT_POSITION = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_SIZE = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_CLOSE = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_DESTROYED = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_GOT_FOCUS = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_LOST_FOCUS = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_KEY_DOWN = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_KEY_UP = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_BUTTON_DOWN = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_BUTTON_UP = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_MOTION = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_ENTER = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_LEAVE = ecore_event_type_new();
+ ECORE_DIRECTFB_EVENT_WHEEL = ecore_event_type_new();
+
+ /* create the hash table for the keynames */
+ _ecore_directfb_key_symbols_hash = eina_hash_int32_new(free);
+ for(i = 0; i < _ecore_directfb_key_symbols_count; i++)
+ {
+ struct keymap *k;
+ k = malloc(sizeof(struct keymap));
+ k->name = _ecore_directfb_key_symbols[i].name;
+ k->string = _ecore_directfb_key_symbols[i].string;
+ eina_hash_add(_ecore_directfb_key_symbols_hash, &_ecore_directfb_key_symbols[i].id, k);
+ }
+ /* create the hash for the windows(key = windowid, val = Ecore_DirectFB_Window struct) */
+ return _ecore_directfb_init_count;
+}
+
+EAPI int
+ecore_directfb_shutdown(void)
+{
+ if (--_ecore_directfb_init_count != 0)
+ return _ecore_directfb_init_count;
+
+ ecore_main_fd_handler_del(_window_event_fd_handler_handle);
+ eina_hash_free(_ecore_directfb_key_symbols_hash);
+
+ if(_ecore_directfb_fullscreen_window_id)
+ {
+ DFBCHECK(_input_event->Release(_input_event));
+ ecore_main_fd_handler_del(_input_event_fd_handler_handle);
+ }
+
+ DFBCHECK(_window_event->Release(_window_event));
+ DFBCHECK(_layer->Release(_layer));
+ DFBCHECK(_dfb->Release(_dfb));
+ eina_log_domain_unregister(_ecore_directfb_log_dom);
+ _ecore_directfb_log_dom = -1;
+ return _ecore_directfb_init_count;
+}
+
diff --git a/src/lib/ecore_directfb/ecore_directfb_keys.h b/src/lib/ecore_directfb/ecore_directfb_keys.h
new file mode 100644
index 0000000000..19cca46e57
--- /dev/null
+++ b/src/lib/ecore_directfb/ecore_directfb_keys.h
@@ -0,0 +1,184 @@
+typedef struct _Ecore_DirectFB_Key_Symbols Ecore_DirectFB_Key_Symbols;
+struct _Ecore_DirectFB_Key_Symbols
+{
+ char *string;
+ char *name;
+ unsigned int id;
+};
+
+static const Ecore_DirectFB_Key_Symbols _ecore_directfb_key_symbols[] = {
+ {"\010", "BackSpace",DIKS_BACKSPACE},
+ {"\011", "Tab", DIKS_TAB},
+ {"\015", "Return", DIKS_RETURN},
+ {"", "Cancel", DIKS_CANCEL},
+ {"", "Escape", DIKS_ESCAPE},
+ {" ", "space", DIKS_SPACE},
+ {"!", "exclam", DIKS_EXCLAMATION_MARK},
+ {"\"", "quotedbl", DIKS_QUOTATION},
+ {"#", "numbersign", DIKS_NUMBER_SIGN},
+ {"$", "dollar", DIKS_DOLLAR_SIGN},
+ {"%", "percent", DIKS_PERCENT_SIGN},
+ {"&", "ampersand", DIKS_AMPERSAND},
+ {"'", "apostrophe", DIKS_APOSTROPHE},
+ {"(", "parenleft", DIKS_PARENTHESIS_LEFT},
+ {")", "parenright", DIKS_PARENTHESIS_RIGHT},
+ {"*", "asterisk", DIKS_ASTERISK},
+ {"+", "plus", DIKS_PLUS_SIGN},
+ {",", "comma", DIKS_COMMA},
+ {"-", "minus", DIKS_MINUS_SIGN},
+ {".", "period", DIKS_PERIOD},
+ {"/", "slash", DIKS_SLASH},
+ {"0", "0", DIKS_0},
+ {"1", "1", DIKS_1},
+ {"2", "2", DIKS_2},
+ {"3", "3", DIKS_3},
+ {"4", "4", DIKS_4},
+ {"5", "5", DIKS_5},
+ {"6", "6", DIKS_6},
+ {"7", "7", DIKS_7},
+ {"8", "8", DIKS_8},
+ {"9", "9", DIKS_9},
+ {":", "colon", DIKS_COLON},
+ {";", "semicolon", DIKS_SEMICOLON},
+ {"<", "less", DIKS_LESS_THAN_SIGN},
+ {"=", "equal", DIKS_EQUALS_SIGN},
+ {">", "greater", DIKS_GREATER_THAN_SIGN},
+ {"?", "question", DIKS_QUESTION_MARK},
+ {"@", "at", DIKS_AT},
+ {"A", "A", DIKS_CAPITAL_A },
+ {"B", "B", DIKS_CAPITAL_B },
+ {"C", "C", DIKS_CAPITAL_C },
+ {"D", "D", DIKS_CAPITAL_D },
+ {"E", "E", DIKS_CAPITAL_E },
+ {"F", "F", DIKS_CAPITAL_F },
+ {"G", "G", DIKS_CAPITAL_G },
+ {"H", "H", DIKS_CAPITAL_H },
+ {"I", "I", DIKS_CAPITAL_I },
+ {"J", "J", DIKS_CAPITAL_J },
+ {"K", "K", DIKS_CAPITAL_K },
+ {"L", "L", DIKS_CAPITAL_L },
+ {"M", "M", DIKS_CAPITAL_M },
+ {"N", "N", DIKS_CAPITAL_N },
+ {"O", "O", DIKS_CAPITAL_O },
+ {"P", "P", DIKS_CAPITAL_P },
+ {"Q", "Q", DIKS_CAPITAL_Q },
+ {"R", "R", DIKS_CAPITAL_R },
+ {"S", "S", DIKS_CAPITAL_S },
+ {"T", "T", DIKS_CAPITAL_T },
+ {"U", "U", DIKS_CAPITAL_U },
+ {"V", "V", DIKS_CAPITAL_V },
+ {"W", "W", DIKS_CAPITAL_W },
+ {"X", "X", DIKS_CAPITAL_X },
+ {"Y", "Y", DIKS_CAPITAL_Y },
+ {"Z", "Z", DIKS_CAPITAL_Z },
+ {"[", "bracketleft", DIKS_SQUARE_BRACKET_LEFT },
+ {"\\", "backslash", DIKS_BACKSLASH },
+ {"]", "bracketright", DIKS_SQUARE_BRACKET_RIGHT },
+ {"^", "asciicircum", DIKS_CIRCUMFLEX_ACCENT },
+ {"_", "underscore", DIKS_UNDERSCORE },
+ {"`", "grave", DIKS_GRAVE_ACCENT},
+ {"a", "a", DIKS_SMALL_A },
+ {"b","b", DIKS_SMALL_B },
+ {"c","c", DIKS_SMALL_C },
+ {"d","d", DIKS_SMALL_D },
+ {"e","e", DIKS_SMALL_E },
+ {"f","f", DIKS_SMALL_F },
+ {"g","g", DIKS_SMALL_G },
+ {"h","h", DIKS_SMALL_H },
+ {"i","i", DIKS_SMALL_I },
+ {"j","j", DIKS_SMALL_J },
+ {"k","k", DIKS_SMALL_K },
+ {"l","l", DIKS_SMALL_L },
+ {"m","m", DIKS_SMALL_M },
+ {"n","n", DIKS_SMALL_N },
+ {"o", "o", DIKS_SMALL_O },
+ {"p", "p", DIKS_SMALL_P },
+ {"q", "q", DIKS_SMALL_Q },
+ {"r", "r", DIKS_SMALL_R },
+ {"s", "s", DIKS_SMALL_S },
+ {"t", "t", DIKS_SMALL_T },
+ {"u", "u", DIKS_SMALL_U },
+ {"v", "v", DIKS_SMALL_V },
+ {"w", "w", DIKS_SMALL_W },
+ {"x", "x", DIKS_SMALL_X },
+ {"y", "y", DIKS_SMALL_Y },
+ {"z", "z", DIKS_SMALL_Z },
+ {"{", "braceleft",DIKS_CURLY_BRACKET_LEFT },
+ {"|", "bar", DIKS_VERTICAL_BAR },
+ {"}", "braceright", DIKS_CURLY_BRACKET_RIGHT },
+ {"~", "asciitilde", DIKS_TILDE },
+ {"\177", "Delete", DIKS_DELETE },
+ {"", "Left", DIKS_CURSOR_LEFT },
+ {"", "Right", DIKS_CURSOR_RIGHT},
+ {"", "Up", DIKS_CURSOR_UP},
+ {"", "Down", DIKS_CURSOR_DOWN},
+ {"", "Insert", DIKS_INSERT},
+ {"", "Home", DIKS_HOME},
+ {"", "End", DIKS_END},
+ {"", "Page_Up", DIKS_PAGE_UP},
+ {"", "Page_Down", DIKS_PAGE_DOWN},
+ {"", "Print", DIKS_PRINT},
+ {"", "Pause", DIKS_PAUSE},
+ /* ok */
+ {"", "Select",DIKS_SELECT},
+ /* goto */
+ {"", "Clear", DIKS_CLEAR},
+ /* power */
+ /* power 2 */
+ /* option */
+ {"", "Menu",DIKS_MENU},
+ {"", "Help",DIKS_HELP},
+ /* info */
+ /* time */
+ /* vendor */
+ /* archive */
+ /* program */
+ /* channel */
+ /* favorites */
+ /* hasta next */
+ {"", "Next",DIKS_NEXT},
+ {"", "Begin",DIKS_BEGIN},
+ /* digits */
+ /* teen */
+ /* twen */
+ {"", "Break", DIKS_BREAK},
+ /* exit */
+ /* setup */
+ {"", "upleftcorner", DIKS_CURSOR_LEFT_UP },
+ {"", "lowleftcorner", DIKS_CURSOR_LEFT_DOWN },
+ {"", "uprightcorner", DIKS_CURSOR_UP_RIGHT },
+ {"", "lowrightcorner",DIKS_CURSOR_DOWN_RIGHT },
+ {"", "F1",DIKS_F1},
+ {"", "F2",DIKS_F2},
+ {"", "F3",DIKS_F3},
+ {"", "F4",DIKS_F4},
+ {"", "F5",DIKS_F5},
+ {"", "F6",DIKS_F6},
+ {"", "F7",DIKS_F7},
+ {"", "F8",DIKS_F8},
+ {"", "F9",DIKS_F9},
+ {"", "F10",DIKS_F10},
+ {"", "F11",DIKS_F11},
+ {"", "F12",DIKS_F12},
+ /* this are only mapped to one, not left right */
+ {"", "Shift_L", DIKS_SHIFT},
+ /*{"Shift_R",0xFFE2},*/
+ {"", "Control_L", DIKS_CONTROL},
+ /*{"Control_R",0xFFE4},*/
+ {"", "Meta_L", DIKS_META},
+ /* {"Meta_R",0xFFE8},*/
+ {"", "Alt_L", DIKS_ALT},
+ {"", "Alt_R", DIKS_ALTGR},
+ {"", "Super_L", DIKS_SUPER},
+ /*{"Super_R",0xFFEC},*/
+ {"", "Hyper_L", DIKS_HYPER},
+ /*{"Hyper_R",0xFFEE},*/
+
+ {"", "Caps_Lock", DIKS_CAPS_LOCK},
+ {"", "Num_Lock", DIKS_NUM_LOCK},
+ {"", "Scroll_Lock", DIKS_SCROLL_LOCK},
+ /* not included the dead keys */
+ /* not included the custom keys */
+ {"", "VoidSymbol", DIKS_NULL}
+};
+static int _ecore_directfb_key_symbols_count = sizeof(_ecore_directfb_key_symbols) / sizeof(Ecore_DirectFB_Key_Symbols);
diff --git a/src/lib/ecore_directfb/ecore_directfb_private.h b/src/lib/ecore_directfb/ecore_directfb_private.h
new file mode 100644
index 0000000000..ed34587ab5
--- /dev/null
+++ b/src/lib/ecore_directfb/ecore_directfb_private.h
@@ -0,0 +1,52 @@
+#ifndef _ECORE_DIRECTFB_PRIVATE_H
+#define _ECORE_DIRECTFB_PRIVATE_H
+/* eina_log related things */
+
+extern int _ecore_directfb_log_dom;
+
+#ifdef ECORE_DIRECTFB_DEFAULT_LOG_COLOR
+#undef ECORE_DIRECTFB_DEFAULT_LOG_COLOR
+#endif /* ifdef ECORE_DIRECTFB_DEFAULT_LOG_COLOR */
+#define ECORE_DIRECTFB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif /* ifdef ERR */
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_directfb_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif /* ifdef DBG */
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_directfb_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif /* ifdef INF */
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_directfb_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif /* ifdef WRN */
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_directfb_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif /* ifdef CRIT */
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_directfb_log_dom, __VA_ARGS__)
+
+/* macro for a safe call to DirectFB functions */
+#define DFBCHECK(x ...)\
+ {\
+ _err = x;\
+ if (_err != DFB_OK) {\
+ CRIT("%s <%d>:\n\t", __FILE__, __LINE__ );\
+ DirectFBErrorFatal( # x, _err );\
+ }\
+ }
+
+struct keymap
+{
+ char *name;
+ char *string;
+};
+#endif /* ifndef _ECORE_DIRECTFB_PRIVATE_H */
diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h
new file mode 100644
index 0000000000..3c59c80c84
--- /dev/null
+++ b/src/lib/ecore_evas/Ecore_Evas.h
@@ -0,0 +1,2256 @@
+#ifndef _ECORE_EVAS_H
+#define _ECORE_EVAS_H
+
+#include <Evas.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_Input.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_EVAS_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_EVAS_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore_Evas.h
+ * @brief Evas wrapper functions
+ *
+ * The following is a list of example that partially exemplify Ecore_Evas's API:
+ * @li @ref ecore_evas_callbacks_example_c
+ * @li @ref ecore_evas_object_example_c
+ * @li @ref ecore_evas_basics_example_c
+ * @li @ref Ecore_Evas_Window_Sizes_Example_c
+ * @li @ref Ecore_Evas_Buffer_Example_01_c
+ * @li @ref Ecore_Evas_Buffer_Example_02_c
+ */
+
+/* FIXME:
+ * to do soon:
+ * - iconfication api needs to work
+ * - maximization api needs to work
+ * - document all calls
+ *
+ * later:
+ * - buffer back-end that renders to an evas_image_object ???
+ * - qt back-end ???
+ * - dfb back-end ??? (dfb's threads make this REALLY HARD)
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_Evas_Group Ecore_Evas wrapper/helper set of functions
+ *
+ * Ecore evas is a set of functions that makes it easy to tie together ecore's
+ * main loop and input handling to evas. As such it's a natural base for EFL
+ * applications. While this combination makes it easy to create the basic
+ * aspects all applications need, for normal applications(ones with buttons,
+ * checkboxes and layouts) one should consider using Elementary.
+ *
+ * Ecore evas is extremely well suited for applications that are not based on
+ * widgets. It has a main loop that delivers events, does basic window handling
+ * and leaves all of the drawing up to the user. This works very well if used
+ * in conjunction with Edje or if doing custom drawing as, for example, is done
+ * in games.
+ *
+ * This is a list of examples of these functions:
+ * @li @ref ecore_evas_basics_example_c
+ * @li @ref ecore_evas_object_example_c
+ * @li @ref ecore_evas_callbacks_example_c
+ * @li @ref Ecore_Evas_Window_Sizes_Example_c
+ * @li @ref Ecore_Evas_Buffer_Example_01_c
+ * @li @ref Ecore_Evas_Buffer_Example_02_c
+ *
+ * @{
+ */
+
+/* these are dummy and just tell u what API levels ecore_evas supports - not if
+ * the actual support is compiled in. you need to query for that separately.
+ */
+#define HAVE_ECORE_EVAS_X 1
+#define HAVE_ECORE_EVAS_FB 1
+#define HAVE_ECORE_EVAS_X11_GL 1
+//#define HAVE_ECORE_EVAS_X11_16 1
+#define HAVE_ECORE_EVAS_DIRECTFB 1
+#define HAVE_ECORE_EVAS_WIN32 1
+#define HAVE_ECORE_EVAS_COCOA 1
+#define HAVE_ECORE_EVAS_SDL 1
+//#define HAVE_ECORE_EVAS_WINCE 1
+#define HAVE_ECORE_EVAS_EWS 1
+#define HAVE_ECORE_EVAS_PSL1GHT 1
+#define HAVE_ECORE_EVAS_WAYLAND_SHM 1
+#define HAVE_ECORE_EVAS_WAYLAND_EGL 1
+
+typedef enum _Ecore_Evas_Engine_Type
+{
+ ECORE_EVAS_ENGINE_SOFTWARE_BUFFER,
+ ECORE_EVAS_ENGINE_SOFTWARE_XLIB,
+ ECORE_EVAS_ENGINE_XRENDER_X11,
+ ECORE_EVAS_ENGINE_OPENGL_X11,
+ ECORE_EVAS_ENGINE_SOFTWARE_XCB,
+ ECORE_EVAS_ENGINE_XRENDER_XCB,
+ ECORE_EVAS_ENGINE_SOFTWARE_GDI,
+ ECORE_EVAS_ENGINE_SOFTWARE_DDRAW,
+ ECORE_EVAS_ENGINE_DIRECT3D,
+ ECORE_EVAS_ENGINE_OPENGL_GLEW,
+ ECORE_EVAS_ENGINE_OPENGL_COCOA,
+ ECORE_EVAS_ENGINE_SOFTWARE_SDL,
+ ECORE_EVAS_ENGINE_DIRECTFB,
+ ECORE_EVAS_ENGINE_SOFTWARE_FB,
+ ECORE_EVAS_ENGINE_SOFTWARE_8_X11,
+ ECORE_EVAS_ENGINE_SOFTWARE_16_X11,
+ ECORE_EVAS_ENGINE_SOFTWARE_16_DDRAW,
+ ECORE_EVAS_ENGINE_SOFTWARE_16_WINCE,
+ ECORE_EVAS_ENGINE_OPENGL_SDL,
+ ECORE_EVAS_ENGINE_EWS,
+ ECORE_EVAS_ENGINE_PSL1GHT,
+ ECORE_EVAS_ENGINE_WAYLAND_SHM,
+ ECORE_EVAS_ENGINE_WAYLAND_EGL
+} Ecore_Evas_Engine_Type;
+
+typedef enum _Ecore_Evas_Avoid_Damage_Type
+{
+ ECORE_EVAS_AVOID_DAMAGE_NONE = 0,
+ ECORE_EVAS_AVOID_DAMAGE_EXPOSE = 1,
+ ECORE_EVAS_AVOID_DAMAGE_BUILT_IN = 2
+} Ecore_Evas_Avoid_Damage_Type;
+
+typedef enum _Ecore_Evas_Object_Associate_Flags
+{
+ ECORE_EVAS_OBJECT_ASSOCIATE_BASE = 0,
+ ECORE_EVAS_OBJECT_ASSOCIATE_STACK = 1 << 0,
+ ECORE_EVAS_OBJECT_ASSOCIATE_LAYER = 1 << 1,
+ ECORE_EVAS_OBJECT_ASSOCIATE_DEL = 1 << 2
+} Ecore_Evas_Object_Associate_Flags;
+
+#ifndef _ECORE_X_H
+#define _ECORE_X_WINDOW_PREDEF
+typedef unsigned int Ecore_X_Window;
+#endif
+
+#ifndef _ECORE_DIRECTFB_H
+#define _ECORE_DIRECTFB_WINDOW_PREDEF
+typedef struct _Ecore_DirectFB_Window Ecore_DirectFB_Window;
+#endif
+
+#ifndef __ECORE_WIN32_H__
+typedef struct _Ecore_Win32_Window Ecore_Win32_Window;
+#endif
+
+#ifndef __ECORE_WINCE_H__
+typedef struct _Ecore_WinCE_Window Ecore_WinCE_Window;
+#endif
+
+#ifndef __ECORE_COCOA_H__
+typedef struct _Ecore_Cocoa_Window Ecore_Cocoa_Window;
+#endif
+
+#ifndef _ECORE_EVAS_PRIVATE_H
+/* basic data types */
+typedef struct _Ecore_Evas Ecore_Evas;
+typedef void (*Ecore_Evas_Event_Cb) (Ecore_Evas *ee); /**< Callback used for several ecore evas events @since 1.2 */
+#endif
+
+#ifndef _ECORE_WAYLAND_H_
+#define _ECORE_WAYLAND_WINDOW_PREDEF
+typedef struct _Ecore_Wl_Window Ecore_Wl_Window;
+#endif
+
+/* module setup/shutdown calls */
+
+EAPI int ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine);
+
+/**
+ * @brief Init the Ecore_Evas system.
+ *
+ * @return How many times the lib has been initialized, 0 indicates failure.
+ *
+ * Set up the Evas wrapper system. Init Evas and Ecore libraries.
+ *
+ * @see ecore_evas_shutdown()
+ */
+EAPI int ecore_evas_init(void);
+/**
+ * @brief Shut down the Ecore_Evas system.
+ *
+ * @return 0 if ecore evas is fully shut down, or > 0 if it still being used.
+ *
+ * This closes the Evas wrapper system down. Shut down Evas and Ecore libraries.
+ *
+ * @see ecore_evas_init()
+ */
+EAPI int ecore_evas_shutdown(void);
+
+EAPI void ecore_evas_app_comp_sync_set(Eina_Bool do_sync);
+EAPI Eina_Bool ecore_evas_app_comp_sync_get(void);
+
+/**
+ * @brief Returns a list of supported engines names.
+ *
+ * @return Newly allocated list with engines names. Engines names
+ * strings are internal and should be considered constants, do not
+ * free or modify them, to free the list use ecore_evas_engines_free().
+ */
+EAPI Eina_List *ecore_evas_engines_get(void);
+/**
+ * @brief Free list returned by ecore_evas_engines_get()
+ *
+ * @param engines list with engines names
+ */
+EAPI void ecore_evas_engines_free(Eina_List *engines);
+/**
+ * @brief Creates a new Ecore_Evas based on engine name and common parameters.
+ *
+ * @param engine_name engine name as returned by
+ * ecore_evas_engines_get() or @c NULL to use environment variable
+ * ECORE_EVAS_ENGINE, that can be undefined and in this case
+ * this call will try to find the first working engine.
+ * @param x horizontal position of window (not supported in all engines)
+ * @param y vertical position of window (not supported in all engines)
+ * @param w width of window
+ * @param h height of window
+ * @param extra_options string with extra parameter, dependent on engines
+ * or @ NULL. String is usually in the form: 'key1=value1;key2=value2'.
+ * Pay attention that when getting that from shell commands, most
+ * consider ';' as the command terminator, so you need to escape
+ * it or use quotes.
+ *
+ * @return Ecore_Evas instance or @c NULL if creation failed.
+ */
+EAPI Ecore_Evas *ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options);
+/**
+ * @brief Set whether an Ecore_Evas has an alpha channel or not.
+ *
+ * @param ee The Ecore_Evas to shape
+ * @param alpha @c EINA_TRUE to enable the alpha channel, @c EINA_FALSE to
+ * disable it
+ *
+ * This function allows you to make an Ecore_Evas translucent using an
+ * alpha channel. See ecore_evas_shaped_set() for details. The difference
+ * between a shaped window and a window with an alpha channel is that an
+ * alpha channel supports multiple levels of transparency, as opposed to
+ * the 1 bit transparency of a shaped window (a pixel is either opaque, or
+ * it's transparent).
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_alpha_set(Ecore_Evas *ee, Eina_Bool alpha);
+/**
+ * @brief Query whether an Ecore_Evas has an alpha channel.
+ * @param ee The Ecore_Evas to query.
+ * @return @c EINA_TRUE if ee has an alpha channel, @c EINA_FALSE if it does
+ * not.
+ *
+ * This function returns @c EINA_TRUE if @p ee has an alpha channel, and
+ * @c EINA_FALSE if it does not.
+ *
+ * @see ecore_evas_alpha_set()
+ */
+EAPI Eina_Bool ecore_evas_alpha_get(const Ecore_Evas *ee);
+/**
+ * @brief Set whether an Ecore_Evas has an transparent window or not.
+ *
+ * @param ee The Ecore_Evas to shape
+ * @param transparent @c EINA_TRUE to enable the transparent window,
+ * @c EINA_FALSE to disable it
+ *
+ * This function sets some translucency options, for more complete support see
+ * ecore_evas_alpha_set().
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_alpha_set()
+ */
+EAPI void ecore_evas_transparent_set(Ecore_Evas *ee, Eina_Bool transparent);
+/**
+ * @brief Query whether an Ecore_Evas is transparent.
+ *
+ * @param ee The Ecore_Evas to query.
+ * @return @c EINA_TRUE if ee is transparent, @c EINA_FALSE if it isn't.
+ *
+ * @see ecore_evas_transparent_set()
+ */
+EAPI Eina_Bool ecore_evas_transparent_get(const Ecore_Evas *ee);
+/**
+ * @brief Get the geometry of an Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas whose geometry y
+ * @param x A pointer to an int to place the x coordinate in
+ * @param y A pointer to an int to place the y coordinate in
+ * @param w A pointer to an int to place the w size in
+ * @param h A pointer to an int to place the h size in
+ *
+ * This function takes four pointers to (already allocated) ints, and places
+ * the geometry of @p ee in them. If any of the parameters is not desired you
+ * may pass @c NULL on them.
+ *
+ * @code
+ * int x, y, w, h;
+ * ecore_evas_geometry_get(ee, &x, &y, &w, &h);
+ * @endcode
+ *
+ * @see ecore_evas_new()
+ * @see ecore_evas_resize()
+ * @see ecore_evas_move()
+ * @see ecore_evas_move_resize()
+ */
+EAPI void ecore_evas_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
+/**
+ * @brief Get the geometry which an Ecore_Evas was latest recently requested.
+ *
+ * @param ee The Ecore_Evas whose geometry y
+ * @param x A pointer to an int to place the x coordinate in
+ * @param y A pointer to an int to place the y coordinate in
+ * @param w A pointer to an int to place the w size in
+ * @param h A pointer to an int to place the h size in
+ *
+ * This function takes four pointers to (already allocated) ints, and places
+ * the geometry which @p ee was latest recently requested . If any of the
+ * parameters is not desired you may pass @c NULL on them.
+ * This function can represent recently requested geometry.
+ * ecore_evas_geometry_get function returns the value is updated after engine
+ * finished request. By comparison, ecore_evas_request_geometry_get returns
+ * recently requested value.
+ *
+ * @code
+ * int x, y, w, h;
+ * ecore_evas_request_geometry_get(ee, &x, &y, &w, &h);
+ * @endcode
+ *
+ * @since 1.1
+ */
+EAPI void ecore_evas_request_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
+/**
+ * @brief Set the focus of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas
+ * @param on @c EINA_TRUE for focus, @c EINA_FALSE to defocus.
+ *
+ * This function focuses @p ee if @p on is @c EINA_TRUE, or unfocuses @p ee if
+ * @p on is @c EINA_FALSE.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_focus_set(Ecore_Evas *ee, Eina_Bool on);
+/**
+ * @brief Query whether an Ecore_Evas' window is focused or not.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return @c EINA_TRUE if @p ee if focused, @c EINA_FALSE if not.
+ *
+ * @see ecore_evas_focus_set()
+ */
+EAPI Eina_Bool ecore_evas_focus_get(const Ecore_Evas *ee);
+/**
+ * @brief Iconify or uniconify an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas
+ * @param on @c EINA_TRUE to iconify, @c EINA_FALSE to uniconify.
+ *
+ * This function iconifies @p ee if @p on is @c EINA_TRUE, or uniconifies @p ee
+ * if @p on is @c EINA_FALSE.
+ *
+ * @note Iconify and minimize are synonyms.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_iconified_set(Ecore_Evas *ee, Eina_Bool on);
+/**
+ * @brief Query whether an Ecore_Evas' window is iconified or not.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return @c EINA_TRUE if @p ee is iconified, @c EINA_FALSE if not.
+ *
+ * @note Iconify and minimize are synonyms.
+ *
+ * @see ecore_evas_iconified_set()
+ */
+EAPI Eina_Bool ecore_evas_iconified_get(const Ecore_Evas *ee);
+/**
+ * @brief Set whether an Ecore_Evas' window is borderless or not.
+ *
+ * @param ee The Ecore_Evas
+ * @param on @c EINA_TRUE for borderless, @c EINA_FALSE for bordered.
+ *
+ * This function makes @p ee borderless if @p on is @c EINA_TRUE, or bordered
+ * if @p on is @c EINA_FALSE.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_borderless_set(Ecore_Evas *ee, Eina_Bool on);
+/**
+ * @brief Query whether an Ecore_Evas' window is borderless or not.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return @c EINA_TRUE if @p ee is borderless, @c EINA_FALSE if not.
+ *
+ * @see ecore_evas_borderless_set()
+ */
+EAPI Eina_Bool ecore_evas_borderless_get(const Ecore_Evas *ee);
+/**
+ * @brief Set whether or not an Ecore_Evas' window is fullscreen.
+ *
+ * @param ee The Ecore_Evas
+ * @param on @c EINA_TRUE fullscreen, @c EINA_FALSE not.
+ *
+ * This function causes @p ee to be fullscreen if @p on is @c EINA_TRUE, or
+ * not if @p on is @c EINA_FALSE.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_fullscreen_set(Ecore_Evas *ee, Eina_Bool on);
+/**
+ * @brief Query whether an Ecore_Evas' window is fullscreen or not.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return @c EINA_TRUE if @p ee is fullscreen, @c EINA_FALSE if not.
+ *
+ * @see ecore_evas_fullscreen_set()
+ */
+EAPI Eina_Bool ecore_evas_fullscreen_get(const Ecore_Evas *ee);
+/**
+ * @brief Set another window that this window is a group member of
+ *
+ * @param ee The Ecore_Evas
+ * @param ee_group The other group member
+ *
+ * If @p ee_group is @c NULL, @p ee is removed from the group, otherwise it is
+ * added. Note that if you free the @p ee_group canvas before @p ee, then
+ * getting the group canvas with ecore_evas_window_group_get() will return
+ * an invalid handle.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_window_group_set(Ecore_Evas *ee, const Ecore_Evas *ee_group);
+/**
+ * @brief Get the canvas group set.
+ *
+ * This returns the handle set by ecore_evas_window_group_set().
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The Canvas group handle
+ *
+ * @see ecore_evas_window_group_set()
+ * @since 1.2
+ */
+EAPI const Ecore_Evas *ecore_evas_window_group_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the aspect ratio of a canvas window
+ *
+ * @param ee The Ecore_Evas
+ * @param aspect The aspect ratio (width divided by height), or 0 to disable
+ *
+ * This sets the desired aspect ratio of a canvas window
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_aspect_set(Ecore_Evas *ee, double aspect);
+/**
+ * @brief Get the aspect ratio of a canvas window
+ *
+ * This returns the value set by ecore_evas_aspect_set().
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The aspect ratio
+ *
+ * @see ecore_evas_aspect_set()
+ * @since 1.2
+ */
+EAPI double ecore_evas_aspect_get(const Ecore_Evas *ee);
+/**
+ * @brief Set The urgent hint flag
+ *
+ * @param ee The Ecore_Evas
+ * @param urgent The urgent state flag
+ *
+ * This sets the "urgent" state hint on a window so the desktop environment
+ * can highlight it somehow.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_urgent_set(Ecore_Evas *ee, Eina_Bool urgent);
+/**
+ * @brief Get the urgent state on the cavas window
+ *
+ * This returns the value set by ecore_evas_urgent_set()
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The urgent state set
+ *
+ * @see ecore_evas_urgent_set()
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_urgent_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the modal state flag on the canvas window
+ *
+ * @param ee The Ecore_Evas
+ * @param modal The modal hint flag
+ *
+ * This hints if the window should be modal (eg if it is also transient
+ * for another window, the other window will maybe be denied focus by
+ * the desktop window manager).
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_modal_set(Ecore_Evas *ee, Eina_Bool modal);
+/**
+ * @brief Get The modal flag
+ *
+ * This returns the value set by ecore_evas_modal_set().
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The modal flag
+ *
+ * @see ecore_evas_modal_set()
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_modal_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the "i demand attention" flag on a canvas window
+ *
+ * @param ee The Ecore_Evas
+ * @param demand The flag state to set
+ *
+ * A window may demand attention now (eg you must enter a password before
+ * continuing), and so it may flag a window with this.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_demand_attention_set(Ecore_Evas *ee, Eina_Bool demand);
+/**
+ * @brief Get the "i demand attention" flag
+ *
+ * This returns the value set by ecore_evas_demand_attention_set().
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The "i demand attention" flag.
+ *
+ * @see ecore_evas_demand_attention_set()
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_demand_attention_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the "focus skip" flag
+ *
+ * @param ee The Ecore_Evas
+ * @param skip The "focus skip" state to set.
+ *
+ * A window may not want to accept focus, be in the taskbar, pager etc.
+ * sometimes (example for a small notification window that hovers around
+ * a taskbar or panel, or hovers around a window until some activity
+ * dismisses it).
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ * @since 1.2
+ */
+EAPI void ecore_evas_focus_skip_set(Ecore_Evas *ee, Eina_Bool skip);
+/**
+ * @brief Get the "focus skip" flag
+ *
+ * This returns the value set by ecore_evas_focus_skip_set().
+ *
+ * @param ee The Ecore_Evas to set
+ * @return The "focus skip" flag.
+ *
+ * @see ecore_evas_focus_skip_set()
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_focus_skip_get(const Ecore_Evas *ee);
+
+/**
+ * @brief Set if this evas should ignore @b all events.
+ *
+ * @param ee The Ecore_Evas whose window's to ignore events.
+ * @param ignore The Ecore_Evas new ignore state.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_ignore_events_set(Ecore_Evas *ee, Eina_Bool ignore);
+/**
+ * @brief Returns the ignore state of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas whose window's ignore events state is returned.
+ * @return The Ecore_Evas window's ignore state.
+ *
+ * @see ecore_evas_ignore_events_set()
+ */
+EAPI Eina_Bool ecore_evas_ignore_events_get(const Ecore_Evas *ee);
+/**
+ * @brief Query whether an Ecore_Evas' window is visible or not.
+ *
+ * @param ee The Ecore_Evas to query.
+ * @return 1 if visible, 0 if not.
+ *
+ * This function queries @p ee and returns 1 if it is visible, and 0 if not.
+ *
+ * @see ecore_evas_show()
+ * @see ecore_evas_hide()
+ */
+EAPI int ecore_evas_visibility_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the layer of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas
+ * @param layer The layer to put @p ee on.
+ *
+ * This function moves @p ee to the layer @p layer.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_lower()
+ * @see ecore_evas_raise()
+ */
+EAPI void ecore_evas_layer_set(Ecore_Evas *ee, int layer);
+/**
+ * @brief Get the layer of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return the layer @p ee's window is on.
+ *
+ * @see ecore_evas_layer_set()
+ * @see ecore_evas_lower()
+ * @see ecore_evas_raise()
+ */
+EAPI int ecore_evas_layer_get(const Ecore_Evas *ee);
+/**
+ * @brief Maximize (or unmaximize) an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas
+ * @param on @c EINA_TRUE to maximize, @c EINA_FALSE to unmaximize.
+ *
+ * This function maximizes @p ee if @p on is @c EINA_TRUE, or unmaximizes @p ee
+ * if @p on is @c EINA_FALSE.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_maximized_set(Ecore_Evas *ee, Eina_Bool on);
+/**
+ * @brief Query whether an Ecore_Evas' window is maximized or not.
+ *
+ * @param ee The Ecore_Evas to set
+ * @return @c EINA_TRUE if @p ee is maximized, @c EINA_FALSE if not.
+ *
+ * @see ecore_evas_maximized_set()
+ */
+EAPI Eina_Bool ecore_evas_maximized_get(const Ecore_Evas *ee);
+/**
+ * @brief Move an Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas to move
+ * @param x The x coordinate to move to
+ * @param y The y coordinate to move to
+ *
+ * This moves @p ee to the screen coordinates (@p x, @p y)
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_new()
+ * @see ecore_evas_resize()
+ * @see ecore_evas_move_resize()
+ */
+EAPI void ecore_evas_move(Ecore_Evas *ee, int x, int y);
+/**
+ * @brief Resize an Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas to move
+ * @param w The w coordinate to resize to
+ * @param h The h coordinate to resize to
+ *
+ * This resizes @p ee to @p w x @p h.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_new()
+ * @see ecore_evas_move()
+ * @see ecore_evas_move_resize()
+ */
+EAPI void ecore_evas_resize(Ecore_Evas *ee, int w, int h);
+/**
+ * @brief Move and resize an Ecore_Evas
+ *
+ * @param ee The Ecore_Evas to move and resize
+ * @param x The x coordinate to move to
+ * @param y The y coordinate to move to
+ * @param w The w coordinate to resize to
+ * @param h The h coordinate to resize to
+ *
+ * This moves @p ee to the screen coordinates (@p x, @p y) and resizes
+ * it to @p w x @p h.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_new()
+ * @see ecore_evas_move()
+ * @see ecore_evas_resize()
+ */
+EAPI void ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h);
+/**
+ * @brief Set the rotation of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas
+ * @param rot the angle (in degrees) of rotation.
+ *
+ * The allowed values of @p rot depend on the engine being used. Most only
+ * allow multiples of 90.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_rotation_with_resize_set()
+ */
+EAPI void ecore_evas_rotation_set(Ecore_Evas *ee, int rot);
+/**
+ * @brief Set the rotation of an Ecore_Evas' window
+ *
+ * @param ee The Ecore_Evas
+ * @param rot the angle (in degrees) of rotation.
+ *
+ * Like ecore_evas_rotation_set(), but it also resizes the window's contents so
+ * that they fit inside the current window geometry.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_rotation_set()
+ */
+EAPI void ecore_evas_rotation_with_resize_set(Ecore_Evas *ee, int rot);
+/**
+ * @brief Get the rotation of an Ecore_Evas' window
+ *
+ * @param ee The Ecore_Evas
+ * @return the angle (in degrees) of rotation.
+ *
+ * @see ecore_evas_rotation_set()
+ * @see ecore_evas_rotation_with_resize_set()
+ */
+EAPI int ecore_evas_rotation_get(const Ecore_Evas *ee);
+/**
+ * @brief Raise an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas to raise.
+ *
+ * This functions raises the Ecore_Evas to the front.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_lower()
+ * @see ecore_evas_layer_set()
+ */
+EAPI void ecore_evas_raise(Ecore_Evas *ee);
+/**
+ * @brief Lower an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas to raise.
+ *
+ * This functions lowers the Ecore_Evas to the back.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ *
+ * @see ecore_evas_raise()
+ * @see ecore_evas_layer_set()
+ */
+EAPI void ecore_evas_lower(Ecore_Evas *ee);
+/**
+ * @brief Set the title of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas whose title you wish to set.
+ * @param t The title
+ *
+ * This function sets the title of @p ee to @p t.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_title_set(Ecore_Evas *ee, const char *t);
+/**
+ * @brief Get the title of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas whose title you wish to get.
+ * @return The title of @p ee.
+ *
+ * This function returns the title of @p ee.
+ *
+ * @see ecore_evas_title_set()
+ */
+EAPI const char *ecore_evas_title_get(const Ecore_Evas *ee);
+/**
+ * @brief Set the name and class of an Ecore_Evas' window.
+ *
+ * @param ee the Ecore_Evas
+ * @param n the name
+ * @param c the class
+ *
+ * This function sets the name of @p ee to @p n, and its class to @p c. The
+ * meaning of @p name and @p class depends on the underlying windowing system.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI void ecore_evas_name_class_set(Ecore_Evas *ee, const char *n, const char *c);
+/**
+ * @brief Get the name and class of an Ecore_Evas' window
+ *
+ * This function gets the name of @p ee into @p n, and its class into
+ * @p c.
+ *
+ * @param ee The Ecore_Evas to query.
+ * @param n A pointer to a string to place the name in.
+ * @param c A pointer to a string to place the class in.
+ * @see ecore_evas_name_class_set()
+ */
+EAPI void ecore_evas_name_class_get(const Ecore_Evas *ee, const char **n, const char **c);
+/**
+ * @brief Returns a pointer to the underlying window.
+ *
+ * @param ee The Ecore_Evas whose window is desired.
+ * @return A pointer to the underlying window.
+ *
+ * @warning Support for this depends on the underlying windowing system.
+ */
+EAPI Ecore_Window ecore_evas_window_get(const Ecore_Evas *ee);
+
+
+/* engine/target specific init calls */
+EAPI Ecore_Evas *ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_evas_software_x11_window_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on);
+EAPI Eina_Bool ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win);
+
+#define ECORE_EVAS_GL_X11_OPT_NONE 0
+#define ECORE_EVAS_GL_X11_OPT_INDIRECT 1
+#define ECORE_EVAS_GL_X11_OPT_VSYNC 2
+#define ECORE_EVAS_GL_X11_OPT_SWAP_MODE 3
+#define ECORE_EVAS_GL_X11_OPT_LAST 4
+
+#define ECORE_EVAS_GL_X11_SWAP_MODE_AUTO 0
+#define ECORE_EVAS_GL_X11_SWAP_MODE_FULL 1
+#define ECORE_EVAS_GL_X11_SWAP_MODE_COPY 2
+#define ECORE_EVAS_GL_X11_SWAP_MODE_DOUBLE 3
+#define ECORE_EVAS_GL_X11_SWAP_MODE_TRIPLE 4
+
+EAPI Ecore_Evas *ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_Evas *ecore_evas_gl_x11_options_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h, const int *opt);
+EAPI Ecore_X_Window ecore_evas_gl_x11_window_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on);
+EAPI Eina_Bool ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win);
+EAPI void ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee, void *data, void (*pre_cb) (void *data, Evas *e), void (*post_cb) (void *data, Evas *e));
+
+EAPI Ecore_Evas *ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_evas_xrender_x11_window_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_xrender_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on);
+EAPI Eina_Bool ecore_evas_xrender_x11_direct_resize_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_xrender_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win);
+
+EAPI Ecore_Evas *ecore_evas_software_x11_8_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_evas_software_x11_8_window_get(const Ecore_Evas *ee);
+EAPI Ecore_X_Window ecore_evas_software_x11_8_subwindow_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_8_direct_resize_set(Ecore_Evas *ee, Eina_Bool on);
+EAPI Eina_Bool ecore_evas_software_x11_8_direct_resize_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_8_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win);
+
+EAPI Ecore_Evas *ecore_evas_software_x11_16_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, Eina_Bool on);
+EAPI Eina_Bool ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win);
+
+EAPI Ecore_Evas *ecore_evas_fb_new(const char *disp_name, int rotation, int w, int h);
+
+EAPI Ecore_Evas *ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w, int h);
+EAPI Ecore_DirectFB_Window *ecore_evas_directfb_window_get(const Ecore_Evas *ee);
+
+
+EAPI Ecore_Evas *ecore_evas_wayland_shm_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame);
+EAPI Ecore_Evas *ecore_evas_wayland_egl_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame);
+EAPI void ecore_evas_wayland_resize(Ecore_Evas *ee, int location);
+EAPI void ecore_evas_wayland_move(Ecore_Evas *ee, int x, int y);
+
+EAPI void ecore_evas_wayland_pointer_set(Ecore_Evas *ee, int hot_x, int hot_y);
+EAPI void ecore_evas_wayland_type_set(Ecore_Evas *ee, int type);
+EAPI Ecore_Wl_Window *ecore_evas_wayland_window_get(const Ecore_Evas *ee);
+
+/**
+ * @brief Create a new @c Ecore_Evas canvas bound to the Evas
+ * @b buffer engine
+ *
+ * @param w The width of the canvas, in pixels
+ * @param h The height of the canvas, in pixels
+ * @return A new @c Ecore_Evas instance or @c NULL, on failure
+ *
+ * This creates a new buffer canvas wrapper, with image data array
+ * @b bound to the ARGB format, 8 bits per pixel.
+ *
+ * This function will allocate the needed pixels array with canonical
+ * @c malloc(). If you wish a custom function to allocate it, consider
+ * using ecore_evas_buffer_allocfunc_new(), instead.
+ *
+ * @note This function actually is a wrapper on
+ * ecore_evas_buffer_allocfunc_new(), using the same @a w and @a h
+ * arguments and canonical @c malloc() and @c free() to the memory
+ * allocation and freeing functions. See that function's documentation
+ * for more details.
+ */
+EAPI Ecore_Evas *ecore_evas_buffer_new(int w, int h);
+
+/**
+ * @brief Create a new @c Ecore_Evas canvas bound to the Evas
+ * @b buffer engine, giving custom allocation and freeing functions for
+ * the canvas memory region
+ *
+ * @param w The width of the canvas, in canvas units
+ * @param h The height of the canvas, in canvas units
+ * @param alloc_func Function to be called to allocate the memory
+ * needed for the new buffer canvas. @a data will be passed the same
+ * value as the @p data of this function, while @a size will be passed
+ * @p w times @p h times @c sizeof(int).
+ * @param free_func Function to be called to free the memory used by
+ * the new buffer canvas. @a data will be passed the same value as the
+ * @p data of this function, while @a pix will be passed the canvas
+ * memory pointer.
+ * @param data Custom data to be passed to the allocation and freeing
+ * functions
+ * @return A new @c Ecore_Evas instance or @c NULL, on failure
+ *
+ * This creates a new buffer canvas wrapper, with image data array
+ * @b bound to the ARGB format, 8 bits per pixel.
+ *
+ * This function is useful when one wants an @c Ecore_Evas buffer
+ * canvas with a custom allocation function, like one getting memory
+ * chunks from a memory pool, for example.
+ *
+ * On any resizing of this @c Ecore_Evas buffer canvas, its image data
+ * will be @b freed, to be allocated again with the new size.
+ *
+ * @note @p w and @p h sizes have to greater or equal to 1. Otherwise,
+ * they'll be interpreted as 1, exactly.
+ *
+ * @see ecore_evas_buffer_new()
+ */
+EAPI Ecore_Evas *ecore_evas_buffer_allocfunc_new(int w, int h, void *(*alloc_func) (void *data, int size), void (*free_func) (void *data, void *pix), const void *data);
+
+/**
+ * @brief Grab a pointer to the actual pixels array of a given
+ * @c Ecore_Evas @b buffer canvas/window.
+ *
+ * @param ee An @c Ecore_Evas handle
+ * @return A pointer to the internal pixels array of @p ee
+ *
+ * Besides returning a pointer to the actual pixel array of the given
+ * canvas, this call will force a <b>rendering update on @p ee</b>,
+ * first.
+ *
+ * A common use case for this call is to create an image object, from
+ * @b another canvas, to have as data @p ee's contents, thus
+ * snapshoting the canvas. For that case, one can also use the
+ * ecore_evas_object_image_new() helper function.
+ */
+EAPI const void *ecore_evas_buffer_pixels_get(Ecore_Evas *ee);
+
+/**
+ * @brief Create a new @c Ecore_Evas canvas bound to the Evas
+ * @b ews (Ecore + Evas Single Process Windowing System) engine
+ *
+ * EWS is a simple single process windowing system. The backing store
+ * is also an @c Ecore_Evas that can be setup with
+ * ecore_evas_ews_setup() and retrieved with
+ * ecore_evas_ews_ecore_evas_get(). It will allow window management
+ * using events prefixed with @c ECORE_EVAS_EVENT_EWS_.
+ *
+ * The EWS windows (returned by this function or
+ * ecore_evas_new("ews"...)) will all be software buffer windows
+ * automatic rendered to the backing store.
+ *
+ * @param x horizontal position of window, in pixels
+ * @param y vertical position of window, in pixels
+ * @param w The width of the canvas, in pixels
+ * @param h The height of the canvas, in pixels
+ * @return A new @c Ecore_Evas instance or @c NULL, on failure
+ *
+ * @see ecore_evas_ews_setup()
+ * @see ecore_evas_ews_ecore_evas_get()
+ *
+ * @since 1.1
+ */
+EAPI Ecore_Evas *ecore_evas_ews_new(int x, int y, int w, int h);
+
+
+/**
+ * Returns the backing store image object that represents the given
+ * window in EWS.
+ * @return The evas object of EWS backing store.
+ *
+ * @note This should not be modified anyhow, but may be helpful to
+ * determine stacking and geometry of it for window managers
+ * that decorate windows.
+ *
+ * @param ee The Ecore_Evas from which to get the backing store.
+ * @see ecore_evas_ews_manager_set()
+ * @see ecore_evas_ews_evas_get()
+ * @since 1.1
+ */
+EAPI Evas_Object *ecore_evas_ews_backing_store_get(const Ecore_Evas *ee);
+
+/**
+ * Calls the window to be deleted (freed), but can let user decide to
+ * forbid it by using ecore_evas_callback_delete_request_set()
+ *
+ * @param ee The Ecore_Evas for which window will be deleted.
+ * @since 1.1
+ */
+EAPI void ecore_evas_ews_delete_request(Ecore_Evas *ee);
+
+/**
+ * @brief Create an Evas image object with image data <b>bound to an
+ * own, internal @c Ecore_Evas canvas wrapper</b>
+ *
+ * @param ee_target @c Ecore_Evas to have the canvas receiving the new
+ * image object
+ * @return A handle to the new image object
+ *
+ * This will create a @b special Evas image object. The image's pixel
+ * array will get bound to the same image data array of an @b internal
+ * @b buffer @c Ecore_Evas canvas. The user of this function is, then,
+ * supposed to grab that @c Ecore_Evas handle, with
+ * ecore_evas_object_ecore_evas_get(), and use its canvas to render
+ * whichever contents he/she wants, @b independently of the contents
+ * of the canvas owned by @p ee_target. Those contents will reflect on
+ * the canvas of @p ee, though, being exactly the image data of the
+ * object returned by this function.
+ *
+ * This is a helper function for the scenario of one wanting to grab a
+ * buffer canvas' contents (with ecore_evas_buffer_pixels_get()) to be
+ * used on another canvas, for whichever reason. The most common goal
+ * of this setup is to @b save an image file with a whole canvas as
+ * contents, which could not be achieved by using an image file within
+ * the target canvas.
+ *
+ * @warning Always resize the returned image and its underlying
+ * @c Ecore_Evas handle accordingly. They must be kept with same sizes
+ * for things to work as expected. Also, you @b must issue
+ * @c evas_object_image_size_set() on the image with that same size. If
+ * the image is to be shown in a canvas bound to an engine different
+ * than the buffer one, then you must also set this image's @b fill
+ * properties accordingly.
+ *
+ * @note The image returned will always be bound to the
+ * @c EVAS_COLORSPACE_ARGB8888 colorspace, always.
+ *
+ * @note Use ecore_evas_object_evas_get() to grab the image's internal
+ * own canvas directly.
+ *
+ * @note If snapshoting this image's internal canvas, remember to
+ * flush its internal @c Ecore_Evas firstly, with
+ * ecore_evas_manual_render().
+ */
+EAPI Evas_Object *ecore_evas_object_image_new(Ecore_Evas *ee_target);
+
+/**
+ * @brief Retrieve the internal @c Ecore_Evas handle of an image
+ * object created via ecore_evas_object_image_new()
+ *
+ * @param obj A handle to an image object created via
+ * ecore_evas_object_image_new()
+ * @return The underlying @c Ecore_Evas handle in @p obj
+ */
+EAPI Ecore_Evas *ecore_evas_object_ecore_evas_get(Evas_Object *obj);
+
+/**
+ * @brief Retrieve the canvas bound to the internal @c Ecore_Evas
+ * handle of an image object created via ecore_evas_object_image_new()
+ *
+ * @param obj A handle to an image object created via
+ * ecore_evas_object_image_new()
+ * @return A handle to @p obj's underlying @c Ecore_Evas's canvas
+ */
+EAPI Evas *ecore_evas_object_evas_get(Evas_Object *obj);
+
+EAPI Ecore_Evas *ecore_evas_software_gdi_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_direct3d_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_gl_glew_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Win32_Window *ecore_evas_win32_window_get(const Ecore_Evas *ee);
+
+EAPI Ecore_Evas *ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha);
+EAPI Ecore_Evas *ecore_evas_sdl16_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha);
+EAPI Ecore_Evas *ecore_evas_gl_sdl_new(const char* name, int w, int h, int fullscreen, int noframe);
+
+EAPI Ecore_Evas *ecore_evas_software_wince_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_wince_fb_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_wince_gapi_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_wince_ddraw_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_Evas *ecore_evas_software_wince_gdi_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI Ecore_WinCE_Window *ecore_evas_software_wince_window_get(const Ecore_Evas *ee);
+
+EAPI Ecore_Evas *ecore_evas_cocoa_new(Ecore_Cocoa_Window *parent,
+ int x,
+ int y,
+ int w,
+ int h);
+
+EAPI Ecore_Evas *ecore_evas_psl1ght_new(const char* name, int w, int h);
+
+
+/* generic manipulation calls */
+/**
+ * @brief Get the engine name used by this Ecore_Evas(window).
+ *
+ * @param ee Ecore_Evas whose engine's name is desired.
+ * @return A string that can(usually) be used in ecore_evas_new()
+ *
+ * @see ecore_evas_free()
+ */
+EAPI const char *ecore_evas_engine_name_get(const Ecore_Evas *ee);
+/**
+ * @brief Return the Ecore_Evas for this Evas
+ *
+ * @param e The Evas to get the Ecore_Evas from
+ * @return The Ecore_Evas that holds this Evas, or @c NULL if not held by one.
+ *
+ * @warning Only use on Evas' created with ecore evas!
+ */
+EAPI Ecore_Evas *ecore_evas_ecore_evas_get(const Evas *e);
+/**
+ * @brief Free an Ecore_Evas
+ *
+ * @param ee The Ecore_Evas to free
+ *
+ * This frees up any memory used by the Ecore_Evas.
+ */
+EAPI void ecore_evas_free(Ecore_Evas *ee);
+/**
+ * @brief Retrieve user data associated with an Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas to retrieve the user data from.
+ * @param key The key which the user data to be retrieved is associated with.
+ *
+ * This function retrieves user specific data that has been stored within an
+ * Ecore_Evas structure with ecore_evas_data_set().
+ *
+ * @returns @c NULL on error or no data found, A pointer to the user data on
+ * success.
+ *
+ * @see ecore_evas_data_set()
+ */
+EAPI void *ecore_evas_data_get(const Ecore_Evas *ee, const char *key);
+/**
+ * @brief Store user data in an Ecore_Evas structure.
+ *
+ * @param ee The Ecore_Evas to store the user data in.
+ * @param key A unique string to associate the user data against. Cannot
+ * be NULL.
+ * @param data A pointer to the user data to store.
+ *
+ * This function associates the @p data with a @p key which is stored by
+ * the Ecore_Evas @p ee. Be aware that a call to ecore_evas_free() will
+ * not free any memory for the associated user data, this is the responsibility
+ * of the caller.
+ *
+ * @see ecore_evas_callback_pre_free_set()
+ * @see ecore_evas_free()
+ * @see ecore_evas_data_get()
+ */
+EAPI void ecore_evas_data_set(Ecore_Evas *ee, const char *key, const void *data);
+/**
+ * Set a callback for Ecore_Evas resize events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee is resized.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas move events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee is moved.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas show events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee is shown.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_show_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas hide events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee is hidden.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_hide_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas delete request events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee gets a delete request.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas destroy events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee is destroyed.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_destroy_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas focus in events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee gets focus.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas focus out events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee loses focus.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas sticky events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee becomes sticky.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_sticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas un-sticky events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee becomes un-sticky.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_unsticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas mouse in events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever the mouse enters @p ee.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas mouse out events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever the mouse leaves @p ee.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas pre render events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called just before the evas in @p ee is rendered.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_pre_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas mouse post render events.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called just after the evas in @p ee is rendered.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_post_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas pre-free event.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+ *
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called just before the instance @p ee is freed.
+ *
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_pre_free_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+/**
+ * Set a callback for Ecore_Evas state changes.
+ * @param ee The Ecore_Evas to set callbacks on
+ * @param func The function to call
+
+ * A call to this function will set a callback on an Ecore_Evas, causing
+ * @p func to be called whenever @p ee changes state.
+ *
+ * @since 1.2
+ * @warning If and when this function is called depends on the underlying
+ * windowing system.
+ */
+EAPI void ecore_evas_callback_state_change_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+
+/**
+ * Get an Ecore_Evas's Evas
+ * @param ee The Ecore_Evas whose Evas you wish to get
+ * @return The Evas wrapped by @p ee
+ *
+ * This function returns the Evas contained within @p ee.
+ */
+EAPI Evas *ecore_evas_get(const Ecore_Evas *ee);
+
+/**
+ * Provide Managed move co-ordinates for an Ecore_Evas
+ * @param ee The Ecore_Evas to move
+ * @param x The x coordinate to set as the managed location
+ * @param y The y coordinate to set as the managed location
+ *
+ * This sets the managed geometry position of the @p ee to (@p x, @p y)
+ */
+EAPI void ecore_evas_managed_move(Ecore_Evas *ee, int x, int y);
+
+/**
+ * Set whether an Ecore_Evas is shaped or not.
+ *
+ * @param ee The Ecore_Evas to shape.
+ * @param shaped @c EINA_TRUE to shape, @c EINA_FALSE to not.
+ *
+ * This function allows one to make an Ecore_Evas shaped to the contents of the
+ * evas. If @p shaped is @c EINA_TRUE, @p ee will be transparent in parts of
+ * the evas that contain no objects. If @p shaped is @c EINA_FALSE, then @p ee
+ * will be rectangular, and parts with no data will show random framebuffer
+ * artifacting. For non-shaped Ecore_Evases, it is recommended to cover the
+ * entire evas with a background object.
+ */
+EAPI void ecore_evas_shaped_set(Ecore_Evas *ee, Eina_Bool shaped);
+
+/**
+ * Query whether an Ecore_Evas is shaped or not.
+ *
+ * @param ee The Ecore_Evas to query.
+ * @return @c EINA_TRUE if shaped, @c EINA_FALSE if not.
+ *
+ * This function returns @c EINA_TRUE if @p ee is shaped, and @c EINA_FALSE if not.
+ */
+EAPI Eina_Bool ecore_evas_shaped_get(const Ecore_Evas *ee);
+/**
+ * @brief Show an Ecore_Evas' window
+ *
+ * @param ee The Ecore_Evas to show.
+ *
+ * This function makes @p ee visible.
+ */
+EAPI void ecore_evas_show(Ecore_Evas *ee);
+/**
+ * @brief Hide an Ecore_Evas' window
+ *
+ * @param ee The Ecore_Evas to hide.
+ *
+ * This function makes @p ee hidden(not visible).
+ */
+EAPI void ecore_evas_hide(Ecore_Evas *ee);
+
+/**
+ * Activate (set focus to, via the window manager) an Ecore_Evas' window.
+ * @param ee The Ecore_Evas to activate.
+ *
+ * This functions activates the Ecore_Evas.
+ */
+EAPI void ecore_evas_activate(Ecore_Evas *ee);
+
+
+/**
+ * Set the minimum size of a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w The minimum width
+ * @param h The minimum height
+ *
+ * This function sets the minimum size of @p ee to be @p w x @p h.
+ * One won't be able to resize that window to dimensions smaller than
+ * the ones set.
+ *
+ * @note When base sizes are set, via ecore_evas_size_base_set(),
+ * they'll be used to calculate a window's minimum size, instead of
+ * those set by this function.
+ *
+ * @see ecore_evas_size_min_get()
+ */
+EAPI void ecore_evas_size_min_set(Ecore_Evas *ee, int w, int h);
+
+/**
+ * Get the minimum size set for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w A pointer to an int to place the minimum width in.
+ * @param h A pointer to an int to place the minimum height in.
+ *
+ * @note Use @c NULL pointers on the size components you're not
+ * interested in: they'll be ignored by the function.
+ *
+ * @see ecore_evas_size_min_set() for more details
+ */
+EAPI void ecore_evas_size_min_get(const Ecore_Evas *ee, int *w, int *h);
+
+/**
+ * Set the maximum size of a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w The maximum width
+ * @param h The maximum height
+ *
+ * This function sets the maximum size of @p ee to be @p w x @p h.
+ * One won't be able to resize that window to dimensions bigger than
+ * the ones set.
+ *
+ * @see ecore_evas_size_max_get()
+ */
+EAPI void ecore_evas_size_max_set(Ecore_Evas *ee, int w, int h);
+
+/**
+ * Get the maximum size set for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w A pointer to an int to place the maximum width in.
+ * @param h A pointer to an int to place the maximum height in.
+ *
+ * @note Use @c NULL pointers on the size components you're not
+ * interested in: they'll be ignored by the function.
+ *
+ * @see ecore_evas_size_max_set() for more details
+ */
+EAPI void ecore_evas_size_max_get(const Ecore_Evas *ee, int *w, int *h);
+
+/**
+ * Set the base size for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w The base width
+ * @param h The base height
+ *
+ * This function sets the @b base size of @p ee to be @p w x @p h.
+ * When base sizes are set, they'll be used to calculate a window's
+ * @b minimum size, instead of those set by ecore_evas_size_min_get().
+ *
+ * @see ecore_evas_size_base_get()
+ */
+EAPI void ecore_evas_size_base_set(Ecore_Evas *ee, int w, int h);
+
+/**
+ * Get the base size set for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w A pointer to an int to place the base width in.
+ * @param h A pointer to an int to place the base height in.
+ *
+ * @note Use @c NULL pointers on the size components you're not
+ * interested in: they'll be ignored by the function.
+ *
+ * @see ecore_evas_size_base_set() for more details
+ */
+EAPI void ecore_evas_size_base_get(const Ecore_Evas *ee, int *w, int *h);
+
+/**
+ * Set the "size step" for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w The step width
+ * @param h The step height
+ *
+ * This function sets the size steps of @p ee to be @p w x @p h. This
+ * limits the size of this @c Ecore_Evas window to be @b always an
+ * integer multiple of the step size, for each axis.
+ */
+EAPI void ecore_evas_size_step_set(Ecore_Evas *ee, int w, int h);
+
+/**
+ * Get the "size step" set for a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas window's handle
+ * @param w A pointer to an int to place the step width in.
+ * @param h A pointer to an int to place the step height in.
+ *
+ * @note Use @c NULL pointers on the size components you're not
+ * interested in: they'll be ignored by the function.
+ *
+ * @see ecore_evas_size_base_set() for more details
+ */
+EAPI void ecore_evas_size_step_get(const Ecore_Evas *ee, int *w, int *h);
+
+/**
+ * @brief Set the cursor of an Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas
+ * @param file The path to an image file for the cursor.
+ * @param layer The layer in which the cursor will appear.
+ * @param hot_x The x coordinate of the cursor's hot spot.
+ * @param hot_y The y coordinate of the cursor's hot spot.
+ *
+ * This function makes the mouse cursor over @p ee be the image specified by
+ * @p file. The actual point within the image that the mouse is at is specified
+ * by @p hot_x and @p hot_y, which are coordinates with respect to the top left
+ * corner of the cursor image.
+ *
+ * @note This function creates an object from the image and uses
+ * ecore_evas_object_cursor_set().
+ *
+ * @see ecore_evas_object_cursor_set()
+ */
+EAPI void ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, int hot_y);
+/**
+ * @brief Get information about an Ecore_Evas' cursor
+ *
+ * @param ee The Ecore_Evas to set
+ * @param obj A pointer to an Evas_Object to place the cursor Evas_Object.
+ * @param layer A pointer to an int to place the cursor's layer in.
+ * @param hot_x A pointer to an int to place the cursor's hot_x coordinate in.
+ * @param hot_y A pointer to an int to place the cursor's hot_y coordinate in.
+ *
+ * This function queries information about an Ecore_Evas' cursor.
+ *
+ * @see ecore_evas_cursor_set()
+ * @see ecore_evas_object_cursor_set()
+ */
+EAPI void ecore_evas_cursor_get(const Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y);
+/**
+ * @brief Set the cursor of an Ecore_Evas
+ *
+ * @param ee The Ecore_Evas
+ *
+ * @param obj The Evas_Object which will be the cursor.
+ * @param layer The layer in which the cursor will appear.
+ * @param hot_x The x coordinate of the cursor's hot spot.
+ * @param hot_y The y coordinate of the cursor's hot spot.
+ *
+ * This function makes the mouse cursor over @p ee be the object specified by
+ * @p obj. The actual point within the object that the mouse is at is specified
+ * by @p hot_x and @p hot_y, which are coordinates with respect to the top left
+ * corner of the cursor object.
+ *
+ * @see ecore_evas_cursor_set()
+ */
+EAPI void ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y);
+
+/**
+ * Tell the WM whether or not to ignore an Ecore_Evas' window
+ *
+ * @param ee The Ecore_Evas.
+ * @param on @c EINA_TRUE to ignore, @c EINA_FALSE to not.
+ *
+ * This function causes the window manager to ignore @p ee if @p on is
+ * @c EINA_TRUE, or not ignore @p ee if @p on is @c EINA_FALSE.
+ */
+EAPI void ecore_evas_override_set(Ecore_Evas *ee, Eina_Bool on);
+
+/**
+ * Query whether an Ecore_Evas' window is overridden or not
+ *
+ * @param ee The Ecore_Evas to set.
+ * @return @c EINA_TRUE if @p ee is overridden, @c EINA_FALSE if not.
+ */
+EAPI Eina_Bool ecore_evas_override_get(const Ecore_Evas *ee);
+
+/**
+ * Set whether or not an Ecore_Evas' window should avoid damage
+ *
+ * @param ee The Ecore_Evas
+ * @param on The type of the damage management
+ *
+ * This option causes updates of the Ecore_Evas to be done on a pixmap, and
+ * then copied to the window, or the pixmap used directly on the window,
+ * depending on the setting. Possible options are:
+ *
+ * @li @ref ECORE_EVAS_AVOID_DAMAGE_NONE - every expose event triggers a new
+ * damage and consequently render of the affected area. The rendering of things
+ * happens directly on the window;
+ *
+ * @li @ref ECORE_EVAS_AVOID_DAMAGE_EXPOSE - there's a pixmap where everything
+ * is rendered into, and then copied to the window. On expose events, there's
+ * no need to render things again, just to copy the exposed region to the
+ * window;
+ *
+ * @li @ref ECORE_EVAS_AVOID_DAMAGE_BUILT_IN - there's the same pixmap as the
+ * previous one, but it is set as a "background pixmap" of the window. The
+ * rendered things appear directly on the window, with no need to copy
+ * anything, but would stay stored on the pixmap, so there's no need to render
+ * things again on expose events. This option can be faster than the previous
+ * one, but may lead to artifacts during resize of the window.
+ */
+EAPI void ecore_evas_avoid_damage_set(Ecore_Evas *ee, Ecore_Evas_Avoid_Damage_Type on);
+
+/**
+ * Query whether an Ecore_Evas' window avoids damage or not
+ * @param ee The Ecore_Evas to set
+ * @return The type of the damage management
+ *
+ */
+EAPI Ecore_Evas_Avoid_Damage_Type ecore_evas_avoid_damage_get(const Ecore_Evas *ee);
+
+/**
+ * Set the withdrawn state of an Ecore_Evas' window.
+ * @param ee The Ecore_Evas whose window's withdrawn state is set.
+ * @param withdrawn The Ecore_Evas window's new withdrawn state.
+ *
+ */
+EAPI void ecore_evas_withdrawn_set(Ecore_Evas *ee, Eina_Bool withdrawn);
+
+/**
+ * Returns the withdrawn state of an Ecore_Evas' window.
+ * @param ee The Ecore_Evas whose window's withdrawn state is returned.
+ * @return The Ecore_Evas window's withdrawn state.
+ *
+ */
+EAPI Eina_Bool ecore_evas_withdrawn_get(const Ecore_Evas *ee);
+
+/**
+ * Set the sticky state of an Ecore_Evas window.
+ *
+ * @param ee The Ecore_Evas whose window's sticky state is set.
+ * @param sticky The Ecore_Evas window's new sticky state.
+ *
+ */
+EAPI void ecore_evas_sticky_set(Ecore_Evas *ee, Eina_Bool sticky);
+
+/**
+ * Returns the sticky state of an Ecore_Evas' window.
+ *
+ * @param ee The Ecore_Evas whose window's sticky state is returned.
+ * @return The Ecore_Evas window's sticky state.
+ *
+ */
+EAPI Eina_Bool ecore_evas_sticky_get(const Ecore_Evas *ee);
+EAPI void ecore_evas_manual_render_set(Ecore_Evas *ee, Eina_Bool manual_render);
+EAPI Eina_Bool ecore_evas_manual_render_get(const Ecore_Evas *ee);
+
+/**
+ * @brief Registers an @c Ecore_Evas to receive events through ecore_input_evas.
+ *
+ * @param ee The @c Ecore_Evas handle.
+ *
+ * This function calls ecore_event_window_register() with the @p ee as its @c
+ * id argument, @c window argument, and uses its @c Evas too. It is useful when
+ * no @c window information is available on a given @c Ecore_Evas backend.
+ *
+ * @see ecore_evas_input_event_unregister()
+ * @since 1.1
+ */
+EAPI void ecore_evas_input_event_register(Ecore_Evas *ee);
+/**
+ * @brief Unregisters an @c Ecore_Evas receiving events through ecore_input_evas.
+ *
+ * @param ee The @c Ecore_Evas handle.
+ *
+ * @see ecore_evas_input_event_register()
+ * @since 1.1
+ */
+EAPI void ecore_evas_input_event_unregister(Ecore_Evas *ee);
+
+/**
+ * @brief Force immediate rendering on a given @c Ecore_Evas window
+ *
+ * @param ee An @c Ecore_Evas handle
+ *
+ * Use this call to forcefully flush the @p ee's canvas rendering
+ * pipeline, thus bring its window to an up to date state.
+ */
+EAPI void ecore_evas_manual_render(Ecore_Evas *ee);
+EAPI void ecore_evas_comp_sync_set(Ecore_Evas *ee, Eina_Bool do_sync);
+EAPI Eina_Bool ecore_evas_comp_sync_get(const Ecore_Evas *ee);
+
+/**
+ * @brief Get geometry of screen associated with this Ecore_Evas.
+ *
+ * @param ee The Ecore_Evas whose window's to query container screen geometry.
+ * @param x where to return the horizontal offset value. May be @c NULL.
+ * @param y where to return the vertical offset value. May be @c NULL.
+ * @param w where to return the width value. May be @c NULL.
+ * @param h where to return the height value. May be @c NULL.
+ *
+ * @since 1.1
+ */
+EAPI void ecore_evas_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
+
+/**
+ * @brief Get the dpi of the screen the Ecore_Evas is primarily on.
+ *
+ * @param ee The Ecore_Evas whose window's to query.
+ * @param xdpi Pointer to integer to store horizontal DPI. May be @c NULL.
+ * @param ydpi Pointer to integer to store vertical DPI. May be @c NULL.
+ *
+ * @since 1.7
+ */
+EAPI void ecore_evas_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi);
+
+EAPI void ecore_evas_draw_frame_set(Ecore_Evas *ee, Eina_Bool draw_frame);
+EAPI Eina_Bool ecore_evas_draw_frame_get(const Ecore_Evas *ee);
+
+/**
+ * @brief Associate the given object to this ecore evas.
+ *
+ * @param ee The Ecore_Evas to associate to @a obj
+ * @param obj The object to associate to @a ee
+ * @param flags The association flags.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * Association means that operations on one will affect the other, for
+ * example moving the object will move the window, resize the object will
+ * also affect the ecore evas window, hide and show applies as well.
+ *
+ * This is meant to simplify development, since you often need to associate
+ * these events with your "base" objects, background or bottom-most object.
+ *
+ * Be aware that some methods might not be what you would like, deleting
+ * either the window or the object will delete the other. If you want to
+ * change that behavior, let's say to hide window when it's closed, you
+ * must use ecore_evas_callback_delete_request_set() and set your own code,
+ * like ecore_evas_hide(). Just remember that if you override delete_request
+ * and still want to delete the window/object, you must do that yourself.
+ *
+ * Since we now define delete_request, deleting windows will not quit
+ * main loop, if you wish to do so, you should listen for EVAS_CALLBACK_FREE
+ * on the object, that way you get notified and you can call
+ * ecore_main_loop_quit().
+ *
+ * Flags can be OR'ed of:
+ * @li ECORE_EVAS_OBJECT_ASSOCIATE_BASE (or 0): to listen to basic events
+ * like delete, resize and move, but no stacking or layer are used.
+ * @li ECORE_EVAS_OBJECT_ASSOCIATE_STACK: stacking operations will act
+ * on the Ecore_Evas, not the object. So evas_object_raise() will
+ * call ecore_evas_raise(). Relative operations (stack_above, stack_below)
+ * are still not implemented.
+ * @li ECORE_EVAS_OBJECT_ASSOCIATE_LAYER: stacking operations will act
+ * on the Ecore_Evas, not the object. So evas_object_layer_set() will
+ * call ecore_evas_layer_set().
+ * @li ECORE_EVAS_OBJECT_ASSOCIATE_DEL: the object delete will delete the
+ * ecore_evas as well as delete_requests on the ecore_evas will delete
+ * etc.
+ */
+EAPI Eina_Bool ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags);
+/**
+ * @brief Cancel the association set with ecore_evas_object_associate().
+ *
+ * @param ee The Ecore_Evas to dissociate from @a obj
+ * @param obj The object to dissociate from @a ee
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj);
+/**
+ * @brief Get the object associated with @p ee
+ *
+ * @param ee The Ecore_Evas to get the object from.
+ * @return The associated object, or @c NULL if there is no associated object.
+ */
+EAPI Evas_Object *ecore_evas_object_associate_get(const Ecore_Evas *ee);
+
+/* helper function to be used with ECORE_GETOPT_CALLBACK_*() */
+EAPI unsigned char ecore_getopt_callback_ecore_evas_list_engines(const Ecore_Getopt *parser, const Ecore_Getopt_Desc *desc, const char *str, void *data, Ecore_Getopt_Value *storage);
+
+/**
+ * @brief Get a list of all the ecore_evases.
+ *
+ * @return A list of ecore_evases.
+ *
+ * The returned list of ecore evases is only valid until the canvases are
+ * destroyed (and should not be cached for instance). The list can be freed by
+ * just deleting the list.
+ */
+EAPI Eina_List *ecore_evas_ecore_evas_list_get(void);
+
+/* specific calls to an x11 environment ecore_evas */
+EAPI void ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_evas_x11_leader_get(Ecore_Evas *ee);
+EAPI void ecore_evas_x11_leader_default_set(Ecore_Evas *ee);
+EAPI void ecore_evas_x11_shape_input_rectangle_set(Ecore_Evas *ee, int x, int y, int w, int h);
+EAPI void ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h);
+EAPI void ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h);
+EAPI void ecore_evas_x11_shape_input_empty(Ecore_Evas *ee);
+EAPI void ecore_evas_x11_shape_input_reset(Ecore_Evas *ee);
+EAPI void ecore_evas_x11_shape_input_apply(Ecore_Evas *ee);
+
+/**
+ * @defgroup Ecore_Evas_Ews Ecore_Evas Single Process Windowing System.
+ *
+ * These are global scope functions to manage the EWS to be used by
+ * ecore_evas_ews_new().
+ *
+ * @since 1.1
+ * @{
+ */
+
+/**
+ * Sets the engine to be used by the backing store engine.
+ *
+ * @param engine The engine to be set.
+ * @param options The options of the engine to be set.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE if ews is already in use.
+ * @since 1.1
+ */
+EAPI Eina_Bool ecore_evas_ews_engine_set(const char *engine, const char *options);
+
+/**
+ * Reconfigure the backing store used.
+ *
+ * @param x The X coordinate to be used.
+ * @param y The Y coordinate to be used.
+ * @param w The width of the Ecore_Evas to setup.
+ * @param h The height of the Ecore_Evas to setup.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @since 1.1
+ */
+EAPI Eina_Bool ecore_evas_ews_setup(int x, int y, int w, int h);
+
+/**
+ * Return the internal backing store in use.
+ *
+ * @return The internal backing store in use.
+ * @note this will forced it to be created, making future calls to
+ * ecore_evas_ews_engine_set() void.
+ *
+ * @see ecore_evas_ews_evas_get()
+ * @since 1.1
+ */
+EAPI Ecore_Evas *ecore_evas_ews_ecore_evas_get(void);
+
+/**
+ * Return the internal backing store in use.
+ *
+ * @return The internal backing store in use.
+ * @note this will forced it to be created, making future calls to
+ * ecore_evas_ews_engine_set() void.
+ *
+ * @see ecore_evas_ews_ecore_evas_get()
+ * @since 1.1
+ */
+EAPI Evas *ecore_evas_ews_evas_get(void);
+
+/**
+ * Get the current background.
+ */
+EAPI Evas_Object *ecore_evas_ews_background_get(void);
+
+/**
+ * Set the current background, must be created at evas ecore_evas_ews_evas_get()
+ *
+ * It will be kept at lowest layer (EVAS_LAYER_MIN) and below
+ * everything else. You can set any object, default is a black
+ * rectangle.
+ *
+ * @note previous object will be deleted!
+ * @param o The Evas_Object for which to set the background.
+ */
+EAPI void ecore_evas_ews_background_set(Evas_Object *o);
+
+/**
+ * Return all Ecore_Evas* created by EWS.
+ *
+ * @return An eina list of Ecore_evases.
+ e @note Do not change the returned list or its contents.
+ * @since 1.1
+ */
+EAPI const Eina_List *ecore_evas_ews_children_get(void);
+
+/**
+ * Set the identifier of the manager taking care of internal windows.
+ *
+ * The ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE event is issued. Consider
+ * handling it to know if you should stop handling events yourself
+ * (ie: another manager took over)
+ *
+ * @param manager any unique identifier address.
+ *
+ * @see ecore_evas_ews_manager_get()
+ * @since 1.1
+ */
+EAPI void ecore_evas_ews_manager_set(const void *manager);
+
+/**
+ * Get the identifier of the manager taking care of internal windows.
+ *
+ * @return the value set by ecore_evas_ews_manager_set()
+ * @since 1.1
+ */
+EAPI const void *ecore_evas_ews_manager_get(void);
+
+EAPI extern int ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE; /**< manager was changed @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_ADD; /**< window was created @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_DEL; /**< window was deleted, pointer is already invalid but may be used as reference for further cleanup work. @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_RESIZE; /**< window was resized @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_MOVE; /**< window was moved @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_SHOW; /**< window become visible @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_HIDE; /**< window become hidden @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_FOCUS; /**< window was focused @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_UNFOCUS; /**< window lost focus @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_RAISE; /**< window was raised @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_LOWER; /**< window was lowered @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_ACTIVATE; /**< window was activated @since 1.1 */
+
+EAPI extern int ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE; /**< window minimized/iconified changed @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE; /**< window maximized changed @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_LAYER_CHANGE; /**< window layer changed @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE; /**< window fullscreen changed @since 1.1 */
+EAPI extern int ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE; /**< some other window property changed (title, name, class, alpha, transparent, shaped...) @since 1.1 */
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup Ecore_Evas_Extn External plug/socket infrastructure to remote canvases
+ *
+ * These functions allow 1 process to create a "socket" was pluged into which another
+ * process can create a "plug" remotely to plug into.
+ * Socket can provides content for several plugs.
+ * This is best for small sized objects (about the size range
+ * of a small icon up to a few large icons). Sine the plug is actually an
+ * image object, you can fetch the pixel data
+ *
+ * @since 1.2
+ * @{
+ */
+
+EAPI extern int ECORE_EVAS_EXTN_CLIENT_ADD; /**< this event is received when a plug has connected to an extn socket @since 1.2 */
+EAPI extern int ECORE_EVAS_EXTN_CLIENT_DEL; /**< this event is received when a plug has disconnected from an extn socket @since 1.2 */
+
+/**
+ * @brief Create a new Ecore_Evas canvas for the new external ecore evas socket
+ *
+ * @param w The width of the canvas, in pixels
+ * @param h The height of the canvas, in pixels
+ * @return A new @c Ecore_Evas instance or @c NULL, on failure
+ *
+ * This creates a new extn_socket canvas wrapper, with image data array
+ * @b bound to the ARGB format, 8 bits per pixel.
+ *
+ * If creation is successful, an Ecore_Evas handle is returned or @c NULL if
+ * creation fails. Also focus, show, hide etc. callbacks will also be called
+ * if the plug object is shown, or already visible on connect, or if it is
+ * hidden later, focused or unfocused.
+ *
+ * This function has to be flowed by ecore_evas_extn_socket_listen(),
+ * for starting ecore ipc service.
+ *
+ * @code
+ * Eina_Bool res = EINA_FALSE;
+ * Ecore_Evas *ee = ecore_evas_extn_socket_new(1, 1);
+ *
+ * res = ecore_evas_extn_socket_listen("svcname", 1, EINA_FALSE);
+ * if (!res) return;
+ * ecore_evas_resize(ee, 240, 400);
+ * @endcode
+ *
+ * or
+ *
+ * @code
+ * Eina_Bool res = EINA_FALSE;
+ * Ecore_Evas *ee = ecore_evas_extn_socket_new(240, 400);
+ *
+ * res = ecore_evas_extn_socket_listen("svcname", 1, EINA_FALSE);
+ * if (!res) return;
+ * @endcode
+ *
+ * When a client(plug) connects, you will get the ECORE_EVAS_EXTN_CLIENT_ADD event
+ * in the ecore event queue, with event_info being the image object pointer
+ * passed as a void pointer. When a client disconnects you will get the
+ * ECORE_EVAS_EXTN_CLIENT_DEL event.
+ *
+ * You can set up event handles for these events as follows:
+ *
+ * @code
+ * static void client_add_cb(void *data, int event, void *event_info)
+ * {
+ * Evas_Object *obj = event_info;
+ * printf("client added to image object %p\n", obj);
+ * evas_object_show(obj);
+ * }
+ *
+ * static void client_del_cb(void *data, int event, void *event_info)
+ * {
+ * Evas_Object *obj = event_info;
+ * printf("client deleted from image object %p\n", obj);
+ * evas_object_hide(obj);
+ * }
+ *
+ * void setup(void)
+ * {
+ * ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_ADD,
+ * client_add_cb, NULL);
+ * ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_DEL,
+ * client_del_cb, NULL);
+ * }
+ * @endcode
+ *
+ * Note that events come in later after the event happened. You may want to be
+ * careful as data structures you had associated with the image object
+ * may have been freed after deleting, but the object may still be around
+ * awating cleanup and thus still be valid.You can change the size with something like:
+ *
+ * @see ecore_evas_extn_socket_listen()
+ * @see ecore_evas_extn_plug_new()
+ * @see ecore_evas_extn_plug_object_data_lock()
+ * @see ecore_evas_extn_plug_object_data_unlock()
+ *
+ * @since 1.2
+ */
+EAPI Ecore_Evas *ecore_evas_extn_socket_new(int w, int h);
+
+/**
+ * @brief Create a socket to provide the service for external ecore evas
+ * socket.
+ *
+ * @param ee The Ecore_Evas.
+ * @param svcname The name of the service to be advertised. ensure that it is
+ * unique (when combined with @p svcnum) otherwise creation may fail.
+ * @param svcnum A number (any value, @c 0 being the common default) to
+ * differentiate multiple instances of services with the same name.
+ * @param svcsys A boolean that if true, specifies to create a system-wide
+ * service all users can connect to, otherwise the service is private to the
+ * user ide that created the service.
+ * @return @c EINA_TRUE if creation is successful, @c EINA_FALSE if it does
+ * not.
+ *
+ * This creates socket specified by @p svcname, @p svcnum and @p svcsys. If
+ * creation is successful, @c EINA_TRUE is returned or @c EINA_FALSE if
+ * creation fails.
+ *
+ * @see ecore_evas_extn_socket_new()
+ * @see ecore_evas_extn_plug_new()
+ * @see ecore_evas_extn_plug_object_data_lock()
+ * @see ecore_evas_extn_plug_object_data_unlock()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_extn_socket_listen(Ecore_Evas *ee, const char *svcname, int svcnum, Eina_Bool svcsys);
+
+/**
+ * @brief Lock the pixel data so the socket cannot change it
+ *
+ * @param obj The image object returned by ecore_evas_extn_plug_new() to lock
+ *
+ * You may need to get the image pixel data with evas_object_image_data_get()
+ * from the image object, but need to ensure that it does not change while
+ * you are using the data. This function lets you set an advisory lock on the
+ * image data so the external plug process will not render to it or alter it.
+ *
+ * You should only hold the lock for just as long as you need to read out the
+ * image data or otherwise deal with it, and then unlock it with
+ * ecore_evas_extn_plug_object_data_unlock(). Keeping a lock over more than
+ * 1 iteration of the main ecore loop will be problematic, so avoid it. Also
+ * forgetting to unlock may cause the socket process to freeze and thus create
+ * odd behavior.
+ *
+ * @see ecore_evas_extn_plug_new()
+ * @see ecore_evas_extn_plug_object_data_unlock()
+ *
+ * @since 1.2
+ */
+EAPI void ecore_evas_extn_plug_object_data_lock(Evas_Object *obj);
+
+/**
+ * @brief Unlock the pixel data so the socket can change it again.
+ *
+ * @param obj The image object returned by ecore_evas_extn_plug_new() to unlock
+ *
+ * This unlocks after an advisor lock has been taken by
+ * ecore_evas_extn_plug_object_data_lock().
+ *
+ * @see ecore_evas_extn_plug_new()
+ * @see ecore_evas_extn_plug_object_data_lock()
+ *
+ * @since 1.2
+ */
+EAPI void ecore_evas_extn_plug_object_data_unlock(Evas_Object *obj);
+
+/**
+ * @brief Create a new external ecore evas plug
+ *
+ * @param ee_target The Ecore_Evas containing the canvas in which the new image object will live.
+ * @return An evas image object that will contain the image output of a socket.
+ *
+ * This creates an image object that will contain the output of another
+ * processes socket canvas when it connects. All input will be sent back to
+ * this process as well, effectively swallowing or placing the socket process
+ * in the canvas of the plug process in place of the image object. The image
+ * object by default is created to be filled (equivalent of
+ * evas_object_image_filled_add() on creation) so image content will scale
+ * to fill the image unless otherwise reconfigured. The Ecore_Evas size
+ * of the plug is the master size and determines size in pixels of the
+ * plug canvas. You can change the size with something like:
+ *
+ * @code
+ * Eina_Bool res = EINA_FALSE;
+ * Evas_Object *obj = ecore_evas_extn_plug_new(ee);
+ *
+ * res = ecore_evas_extn_plug_connect("svcname", 1, EINA_FALSE);
+ * if (!res) return;
+ * ecore_evas_resize(ee, 240, 400);
+ * @endcode
+ *
+ * @see ecore_evas_extn_socket_new()
+ * @see ecore_evas_extn_plug_connect()
+ * @since 1.2
+ */
+EAPI Evas_Object *ecore_evas_extn_plug_new(Ecore_Evas *ee_target);
+
+/**
+ * @brief Connect an external ecore evas plug to service provided by external
+ * ecore evas socket.
+ *
+ * @param obj The Ecore_Evas containing the canvas in which the new image
+ * object will live.
+ * @param svcname The service name to connect to set up by the socket.
+ * @param svcnum The service number to connect to (set up by socket).
+ * @param svcsys Boolean to set if the service is a system one or not (set up
+ * by socket).
+ * @return @c EINA_TRUE if creation is successful, @c EINA_FALSE if it does
+ * not.
+ *
+ * @see ecore_evas_extn_plug_new()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_evas_extn_plug_connect(Evas_Object *obj, const char *svcname, int svcnum, Eina_Bool svcsys);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c
new file mode 100644
index 0000000000..3d841e7db6
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas.c
@@ -0,0 +1,2781 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Input.h"
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+Eina_Bool _ecore_evas_app_comp_sync = 1;
+int _ecore_evas_log_dom = -1;
+static int _ecore_evas_init_count = 0;
+static Ecore_Fd_Handler *_ecore_evas_async_events_fd = NULL;
+static Eina_Bool _ecore_evas_async_events_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
+
+static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL;
+static Ecore_Evas *ecore_evases = NULL;
+static int _ecore_evas_fps_debug = 0;
+
+static Eina_Bool
+_ecore_evas_idle_enter(void *data EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ double t1 = 0.0;
+ double t2 = 0.0;
+ int rend = 0;
+
+ if (!ecore_evases) return ECORE_CALLBACK_RENEW;
+ if (_ecore_evas_fps_debug)
+ {
+ t1 = ecore_time_get();
+ }
+ EINA_INLIST_FOREACH(ecore_evases, ee)
+ {
+ if (!ee->manual_render)
+ {
+ if (ee->engine.func->fn_render)
+ rend |= ee->engine.func->fn_render(ee);
+ }
+ }
+ if (_ecore_evas_fps_debug)
+ {
+ t2 = ecore_time_get();
+ if (rend)
+ _ecore_evas_fps_debug_rendertime_add(t2 - t1);
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+/**
+ * Query if a particular rendering engine target has support
+ * @param engine The engine to check support for
+ * @return 1 if the particular engine is supported, 0 if it is not
+ *
+ * Query if engine @param engine is supported by ecore_evas. 1 is returned if
+ * it is, and 0 is returned if it is not supported.
+ */
+EAPI int
+ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine)
+{
+ switch (engine)
+ {
+ case ECORE_EVAS_ENGINE_SOFTWARE_BUFFER:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_SOFTWARE_XLIB:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_XLIB
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_XRENDER_X11:
+ return EINA_FALSE;
+ case ECORE_EVAS_ENGINE_OPENGL_X11:
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_SOFTWARE_XCB:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_XRENDER_XCB:
+ return EINA_FALSE;
+ case ECORE_EVAS_ENGINE_SOFTWARE_GDI:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_SOFTWARE_DDRAW:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_DIRECT3D:
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_OPENGL_GLEW:
+#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_SOFTWARE_SDL:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_OPENGL_SDL:
+#ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_DIRECTFB:
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_SOFTWARE_FB:
+#ifdef BUILD_ECORE_EVAS_FB
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+
+ case ECORE_EVAS_ENGINE_SOFTWARE_8_X11:
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+
+ case ECORE_EVAS_ENGINE_SOFTWARE_16_X11:
+ return EINA_FALSE;
+ case ECORE_EVAS_ENGINE_SOFTWARE_16_DDRAW:
+ return EINA_FALSE;
+ case ECORE_EVAS_ENGINE_SOFTWARE_16_WINCE:
+ return EINA_FALSE;
+
+ case ECORE_EVAS_ENGINE_OPENGL_COCOA:
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_EWS:
+#ifdef BUILD_ECORE_EVAS_EWS
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_PSL1GHT:
+#ifdef BUILD_ECORE_EVAS_PSL1GHT
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_WAYLAND_SHM:
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ case ECORE_EVAS_ENGINE_WAYLAND_EGL:
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+ default:
+ return EINA_FALSE;
+ };
+}
+
+static void
+_ecore_evas_fork_cb(void *data EINA_UNUSED)
+{
+ int fd;
+
+ if (_ecore_evas_async_events_fd)
+ ecore_main_fd_handler_del(_ecore_evas_async_events_fd);
+ fd = evas_async_events_fd_get();
+ if (fd >= 0)
+ _ecore_evas_async_events_fd =
+ ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ _ecore_evas_async_events_fd_handler, NULL,
+ NULL, NULL);
+}
+
+EAPI int
+ecore_evas_init(void)
+{
+ int fd;
+
+ if (++_ecore_evas_init_count != 1)
+ return _ecore_evas_init_count;
+
+ if (!evas_init())
+ return --_ecore_evas_init_count;
+
+ if (!ecore_init())
+ goto shutdown_evas;
+
+ _ecore_evas_log_dom = eina_log_domain_register
+ ("ecore_evas", ECORE_EVAS_DEFAULT_LOG_COLOR);
+ if(_ecore_evas_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for Ecore_Evas.");
+ goto shutdown_ecore;
+ }
+
+ ecore_fork_reset_callback_add(_ecore_evas_fork_cb, NULL);
+ fd = evas_async_events_fd_get();
+ if (fd >= 0)
+ _ecore_evas_async_events_fd =
+ ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ _ecore_evas_async_events_fd_handler, NULL,
+ NULL, NULL);
+
+ ecore_evas_idle_enterer =
+ ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL);
+ if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1;
+ if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init();
+
+#ifdef BUILD_ECORE_EVAS_EWS
+ _ecore_evas_ews_events_init();
+#endif
+
+ _ecore_evas_extn_init();
+
+ if (getenv("ECORE_EVAS_COMP_NOSYNC"))
+ _ecore_evas_app_comp_sync = 0;
+ return _ecore_evas_init_count;
+
+ shutdown_ecore:
+ ecore_shutdown();
+ shutdown_evas:
+ evas_shutdown();
+
+ return --_ecore_evas_init_count;
+}
+
+EAPI int
+ecore_evas_shutdown(void)
+{
+ if (--_ecore_evas_init_count != 0)
+ return _ecore_evas_init_count;
+
+ while (ecore_evases) _ecore_evas_free(ecore_evases);
+
+ _ecore_evas_extn_shutdown();
+
+ if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown();
+ ecore_idle_enterer_del(ecore_evas_idle_enterer);
+ ecore_evas_idle_enterer = NULL;
+
+#ifdef BUILD_ECORE_EVAS_X11
+ while (_ecore_evas_x_shutdown());
+#endif
+#ifdef BUILD_ECORE_EVAS_WIN32
+ while (_ecore_evas_win32_shutdown());
+#endif
+#ifdef BUILD_ECORE_EVAS_FB
+ while (_ecore_evas_fb_shutdown());
+#endif
+#ifdef BUILD_ECORE_EVAS_EWS
+ while (_ecore_evas_ews_shutdown());
+#endif
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ while (_ecore_evas_buffer_shutdown());
+#endif
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+ while (_ecore_evas_directfb_shutdown());
+#endif
+
+ if (_ecore_evas_async_events_fd)
+ ecore_main_fd_handler_del(_ecore_evas_async_events_fd);
+
+ ecore_fork_reset_callback_del(_ecore_evas_fork_cb, NULL);
+
+ eina_log_domain_unregister(_ecore_evas_log_dom);
+ _ecore_evas_log_dom = -1;
+ ecore_shutdown();
+ evas_shutdown();
+
+ return _ecore_evas_init_count;
+}
+
+EAPI void
+ecore_evas_app_comp_sync_set(Eina_Bool do_sync)
+{
+ _ecore_evas_app_comp_sync = do_sync;
+}
+
+EAPI Eina_Bool
+ecore_evas_app_comp_sync_get(void)
+{
+ return _ecore_evas_app_comp_sync;
+}
+
+struct ecore_evas_engine {
+ const char *name;
+ Ecore_Evas *(*constructor)(int x, int y, int w, int h, const char *extra_options);
+};
+
+/* inline is just to avoid need to ifdef around it */
+static inline const char *
+_ecore_evas_parse_extra_options_str(const char *extra_options, const char *key, char **value)
+{
+ int len = strlen(key);
+
+ while (extra_options)
+ {
+ const char *p;
+
+ if (strncmp(extra_options, key, len) != 0)
+ {
+ extra_options = strchr(extra_options, ';');
+ if (extra_options)
+ extra_options++;
+ continue;
+ }
+
+ extra_options += len;
+ p = strchr(extra_options, ';');
+ if (p)
+ {
+ len = p - extra_options;
+ *value = malloc(len + 1);
+ memcpy(*value, extra_options, len);
+ (*value)[len] = '\0';
+ extra_options = p + 1;
+ }
+ else
+ {
+ *value = strdup(extra_options);
+ extra_options = NULL;
+ }
+ }
+ return extra_options;
+}
+
+/* inline is just to avoid need to ifdef around it */
+static inline const char *
+_ecore_evas_parse_extra_options_uint(const char *extra_options, const char *key, unsigned int *value)
+{
+ int len = strlen(key);
+
+ while (extra_options)
+ {
+ const char *p;
+
+ if (strncmp(extra_options, key, len) != 0)
+ {
+ extra_options = strchr(extra_options, ';');
+ if (extra_options)
+ extra_options++;
+ continue;
+ }
+
+ extra_options += len;
+ *value = strtol(extra_options, NULL, 0);
+
+ p = strchr(extra_options, ';');
+ if (p)
+ extra_options = p + 1;
+ else
+ extra_options = NULL;
+ }
+ return extra_options;
+}
+
+/* inline is just to avoid need to ifdef around it */
+static inline const char *
+_ecore_evas_parse_extra_options_x(const char *extra_options, char **disp_name, unsigned int *parent)
+{
+ _ecore_evas_parse_extra_options_str(extra_options, "display=", disp_name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "parent=", parent);
+ return extra_options;
+}
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+static Ecore_Evas *
+_ecore_evas_constructor_software_x11(int x, int y, int w, int h, const char *extra_options)
+{
+ unsigned int parent = 0;
+ char *disp_name = NULL;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent);
+ ee = ecore_evas_software_x11_new(disp_name, parent, x, y, w, h);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+static Ecore_Evas *
+_ecore_evas_constructor_cocoa(int x, int y, int w, int h, const char *extra_options)
+{
+ char *name = NULL;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "name=", &name);
+ ee = ecore_evas_cocoa_new(NULL, x, y, w, h);
+ free(name);
+
+ if (ee) ecore_evas_move(ee, x, y);
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+static Ecore_Evas *
+_ecore_evas_constructor_opengl_x11(int x, int y, int w, int h, const char *extra_options)
+{
+ Ecore_X_Window parent = 0;
+ char *disp_name = NULL;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent);
+ ee = ecore_evas_gl_x11_new(disp_name, parent, x, y, w, h);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11
+static Ecore_Evas *
+_ecore_evas_constructor_software_8_x11(int x, int y, int w, int h, const char *extra_options)
+{
+ Ecore_X_Window parent = 0;
+ char *disp_name = NULL;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent);
+ ee = ecore_evas_software_x11_8_new(disp_name, parent, x, y, w, h);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL
+static Ecore_Evas *
+_ecore_evas_constructor_sdl(int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, const char *extra_options)
+{
+ Ecore_Evas *ee;
+ unsigned int fullscreen = 0, hwsurface = 0, noframe = 0, alpha = 0;
+ char *name = NULL;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "name=", &name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "fullscreen=", &fullscreen);
+ _ecore_evas_parse_extra_options_uint(extra_options, "hwsurface=", &hwsurface);
+ _ecore_evas_parse_extra_options_uint(extra_options, "noframe=", &noframe);
+ _ecore_evas_parse_extra_options_uint(extra_options, "alpha=", &alpha);
+
+ ee = ecore_evas_sdl_new(name, w, h, fullscreen, hwsurface, noframe, alpha);
+ free(name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+static Ecore_Evas *
+_ecore_evas_constructor_opengl_sdl(int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, const char *extra_options)
+{
+ Ecore_Evas *ee;
+ unsigned int fullscreen = 0, noframe = 0;
+ char *name = NULL;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "name=", &name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "fullscreen=", &fullscreen);
+ _ecore_evas_parse_extra_options_uint(extra_options, "noframe=", &noframe);
+
+ ee = ecore_evas_gl_sdl_new(name, w, h, fullscreen, noframe);
+ free(name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+static Ecore_Evas *
+_ecore_evas_constructor_directfb(int x, int y, int w, int h, const char *extra_options)
+{
+ Ecore_Evas *ee;
+ char *disp_name = NULL;
+ unsigned int windowed = 1;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "windowed=", &windowed);
+
+ ee = ecore_evas_directfb_new(disp_name, windowed, x, y, w, h);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_FB
+static Ecore_Evas *
+_ecore_evas_constructor_fb(int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, const char *extra_options)
+{
+ Ecore_Evas *ee;
+ char *disp_name = NULL;
+ unsigned int rotation = 0;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "rotation=", &rotation);
+
+ ee = ecore_evas_fb_new(disp_name, rotation, w, h);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+
+#ifdef BUILD_ECORE_EVAS_PSL1GHT
+static Ecore_Evas *
+_ecore_evas_constructor_psl1ght(int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, const char *extra_options)
+{
+ Ecore_Evas *ee;
+ char *name = NULL;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "name=", &name);
+ ee = ecore_evas_psl1ght_new(name, w, h);
+ free(name);
+
+ if (ee) ecore_evas_move(ee, x, y);
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+static Ecore_Evas *
+_ecore_evas_constructor_wayland_shm(int x, int y, int w, int h, const char *extra_options)
+{
+ char *disp_name = NULL;
+ unsigned int frame = 1, parent = 0;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "frame=", &frame);
+ _ecore_evas_parse_extra_options_uint(extra_options, "parent=", &parent);
+ ee = ecore_evas_wayland_shm_new(disp_name, parent, x, y, w, h, frame);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+static Ecore_Evas *
+_ecore_evas_constructor_wayland_egl(int x, int y, int w, int h, const char *extra_options)
+{
+ char *disp_name = NULL;
+ unsigned int frame = 1, parent = 0;
+ Ecore_Evas *ee;
+
+ _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name);
+ _ecore_evas_parse_extra_options_uint(extra_options, "frame=", &frame);
+ _ecore_evas_parse_extra_options_uint(extra_options, "parent=", &parent);
+ ee = ecore_evas_wayland_egl_new(disp_name, parent, x, y, w, h, frame);
+ free(disp_name);
+
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+static Ecore_Evas *
+_ecore_evas_constructor_software_gdi(int x, int y, int w, int h, const char *extra_options)
+{
+ return ecore_evas_software_gdi_new(NULL, x, y, w, h);
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+static Ecore_Evas *
+_ecore_evas_constructor_software_ddraw(int x, int y, int w, int h, const char *extra_options)
+{
+ return ecore_evas_software_ddraw_new(NULL, x, y, w, h);
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+static Ecore_Evas *
+_ecore_evas_constructor_direct3d(int x, int y, int w, int h, const char *extra_options)
+{
+ return ecore_evas_direct3d_new(NULL, x, y, w, h);
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+static Ecore_Evas *
+_ecore_evas_constructor_opengl_glew(int x, int y, int w, int h, const char *extra_options)
+{
+ return ecore_evas_gl_glew_new(NULL, x, y, w, h);
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+static Ecore_Evas *
+_ecore_evas_constructor_buffer(int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, const char *extra_options EINA_UNUSED)
+{
+ return ecore_evas_buffer_new(w, h);
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_EWS
+static Ecore_Evas *
+_ecore_evas_constructor_ews(int x, int y, int w, int h, const char *extra_options EINA_UNUSED)
+{
+ return ecore_evas_ews_new(x, y, w, h);
+}
+#endif
+
+/* note: keep sorted by priority, highest first */
+static const struct ecore_evas_engine _engines[] = {
+ /* unix */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ {"software_x11", _ecore_evas_constructor_software_x11},
+#endif
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+ {"opengl_x11", _ecore_evas_constructor_opengl_x11},
+#endif
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11
+ {"software_8_x11", _ecore_evas_constructor_software_8_x11},
+#endif
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+ {"directfb", _ecore_evas_constructor_directfb},
+#endif
+#ifdef BUILD_ECORE_EVAS_FB
+ {"fb", _ecore_evas_constructor_fb},
+#endif
+
+ /* windows */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ {"software_gdi", _ecore_evas_constructor_software_gdi},
+#endif
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+ {"software_ddraw", _ecore_evas_constructor_software_ddraw},
+#endif
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+ {"direct3d", _ecore_evas_constructor_direct3d},
+#endif
+#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+ {"opengl_glew", _ecore_evas_constructor_opengl_glew},
+#endif
+
+ /* Apple */
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+ {"opengl_cocoa", _ecore_evas_constructor_cocoa},
+#endif
+
+ /* PS3 support */
+#ifdef BUILD_ECORE_EVAS_PSL1GHT
+ {"psl1ght", _ecore_evas_constructor_psl1ght},
+#endif
+
+ /* Wayland */
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+ {"wayland_shm", _ecore_evas_constructor_wayland_shm},
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+ {"wayland_egl", _ecore_evas_constructor_wayland_egl},
+#endif
+
+ /* Last chance to have a window */
+#ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+ {"opengl_sdl", _ecore_evas_constructor_opengl_sdl},
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL
+ {"sdl", _ecore_evas_constructor_sdl},
+#endif
+
+ /* independent */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ {"buffer", _ecore_evas_constructor_buffer},
+#endif
+
+#ifdef BUILD_ECORE_EVAS_EWS
+ {"ews", _ecore_evas_constructor_ews},
+#endif
+ {NULL, NULL}
+};
+
+EAPI Eina_List *
+ecore_evas_engines_get(void)
+{
+ const struct ecore_evas_engine *itr;
+ Eina_List *lst = NULL;
+
+ for (itr = _engines; itr->name; itr++)
+ lst = eina_list_append(lst, itr->name);
+
+ return lst;
+}
+
+EAPI void
+ecore_evas_engines_free(Eina_List *engines)
+{
+ eina_list_free(engines);
+}
+
+static Ecore_Evas *
+_ecore_evas_new_auto_discover(int x, int y, int w, int h, const char *extra_options)
+{
+ const struct ecore_evas_engine *itr;
+
+ DBG("auto discover engine");
+
+ for (itr = _engines; itr->constructor; itr++)
+ {
+ Ecore_Evas *ee = itr->constructor(x, y, w, h, extra_options);
+ if (ee)
+ {
+ INF("auto discovered '%s'", itr->name);
+ return ee;
+ }
+ }
+
+ WRN("could not auto discover.");
+ return NULL;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options)
+{
+ const struct ecore_evas_engine *itr;
+
+ if (!engine_name)
+ {
+ engine_name = getenv("ECORE_EVAS_ENGINE");
+ if (engine_name)
+ DBG("no engine_name provided, using ECORE_EVAS_ENGINE='%s'",
+ engine_name);
+ }
+ if (!engine_name)
+ return _ecore_evas_new_auto_discover(x, y, w, h, extra_options);
+
+ for (itr = _engines; itr->name; itr++)
+ if (strcmp(itr->name, engine_name) == 0)
+ {
+ INF("using engine '%s', extra_options=%s",
+ engine_name, extra_options ? extra_options : "(null)");
+ return itr->constructor(x, y, w, h, extra_options);
+ }
+
+ WRN("unknown engine '%s'", engine_name);
+ return NULL;
+}
+
+EAPI const char *
+ecore_evas_engine_name_get(const Ecore_Evas *ee)
+{
+ if (!ee)
+ return NULL;
+ return ee->driver;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_ecore_evas_get(const Evas *e)
+{
+ Ecore_Evas *ee = evas_data_attach_get(e);
+ if (!ee) return NULL;
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_ecore_evas_get");
+ return NULL;
+ }
+ return ee;
+}
+
+EAPI void
+ecore_evas_free(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_free");
+ return;
+ }
+ _ecore_evas_free(ee);
+ return;
+}
+
+EAPI void *
+ecore_evas_data_get(const Ecore_Evas *ee, const char *key)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_data_get");
+ return NULL;
+ }
+
+ if (!key) return NULL;
+ if (!ee->data) return NULL;
+
+ return eina_hash_find(ee->data, key);
+}
+
+EAPI void
+ecore_evas_data_set(Ecore_Evas *ee, const char *key, const void *data)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_data_set");
+ return;
+ }
+
+ if (!key) return;
+
+ if (ee->data)
+ eina_hash_del(ee->data, key, NULL);
+ if (data)
+ {
+ if (!ee->data)
+ ee->data = eina_hash_string_superfast_new(NULL);
+ eina_hash_add(ee->data, key, data);
+ }
+}
+
+#define IFC(_ee, _fn) if (_ee->engine.func->_fn) {_ee->engine.func->_fn
+#define IFE return;}
+
+EAPI void
+ecore_evas_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_resize_set");
+ return;
+ }
+ IFC(ee, fn_callback_resize_set) (ee, func);
+ IFE;
+ ee->func.fn_resize = func;
+}
+
+EAPI void
+ecore_evas_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_move_set");
+ return;
+ }
+ IFC(ee, fn_callback_move_set) (ee, func);
+ IFE;
+ ee->func.fn_move = func;
+}
+
+EAPI void
+ecore_evas_callback_show_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_show_set");
+ return;
+ }
+ IFC(ee, fn_callback_show_set) (ee, func);
+ IFE;
+ ee->func.fn_show = func;
+}
+
+EAPI void
+ecore_evas_callback_hide_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_hide_set");
+ return;
+ }
+ IFC(ee, fn_callback_hide_set) (ee, func);
+ IFE;
+ ee->func.fn_hide = func;
+}
+
+EAPI void
+ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_delete_request_set");
+ return;
+ }
+ IFC(ee, fn_callback_delete_request_set) (ee, func);
+ IFE;
+ ee->func.fn_delete_request = func;
+}
+
+EAPI void
+ecore_evas_callback_destroy_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_destroy_set");
+ return;
+ }
+ IFC(ee, fn_callback_destroy_set) (ee, func);
+ IFE;
+ ee->func.fn_destroy = func;
+}
+
+EAPI void
+ecore_evas_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_focus_in_set");
+ return;
+ }
+ IFC(ee, fn_callback_focus_in_set) (ee, func);
+ IFE;
+ ee->func.fn_focus_in = func;
+}
+
+EAPI void
+ecore_evas_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_focus_out_set");
+ return;
+ }
+ IFC(ee, fn_callback_focus_out_set) (ee, func);
+ IFE;
+ ee->func.fn_focus_out = func;
+}
+
+EAPI void
+ecore_evas_callback_sticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_sticky_set");
+ return;
+ }
+ IFC(ee, fn_callback_sticky_set) (ee, func);
+ IFE;
+ ee->func.fn_sticky = func;
+}
+
+EAPI void
+ecore_evas_callback_unsticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_unsticky_set");
+ return;
+ }
+ IFC(ee, fn_callback_unsticky_set) (ee, func);
+ IFE;
+ ee->func.fn_unsticky = func;
+}
+
+EAPI void
+ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_mouse_in_set");
+ return;
+ }
+ IFC(ee, fn_callback_mouse_in_set) (ee, func);
+ IFE;
+ ee->func.fn_mouse_in = func;
+}
+
+EAPI void
+ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_mouse_out_set");
+ return;
+ }
+ IFC(ee, fn_callback_mouse_out_set) (ee, func);
+ IFE;
+ ee->func.fn_mouse_out = func;
+}
+
+EAPI void
+ecore_evas_callback_pre_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_pre_render_set");
+ return;
+ }
+ IFC(ee, fn_callback_pre_render_set) (ee, func);
+ IFE;
+ ee->func.fn_pre_render = func;
+}
+
+EAPI void
+ecore_evas_callback_post_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_post_render_set");
+ return;
+ }
+ IFC(ee, fn_callback_post_render_set) (ee, func);
+ IFE;
+ ee->func.fn_post_render = func;
+}
+
+EAPI void
+ecore_evas_callback_pre_free_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_pre_free_set");
+ return;
+ }
+ ee->func.fn_pre_free = func;
+}
+
+EAPI void
+ecore_evas_callback_state_change_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_callback_state_change_set");
+ return;
+ }
+ ee->func.fn_state_change = func;
+}
+
+EAPI Evas *
+ecore_evas_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_get");
+ return NULL;
+ }
+ return ee->evas;
+}
+
+EAPI void
+ecore_evas_move(Ecore_Evas *ee, int x, int y)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_move");
+ return;
+ }
+ if (ee->prop.fullscreen) return;
+ IFC(ee, fn_move) (ee, x, y);
+ IFE;
+}
+
+EAPI void
+ecore_evas_managed_move(Ecore_Evas *ee, int x, int y)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_move");
+ return;
+ }
+ IFC(ee, fn_managed_move) (ee, x, y);
+ IFE;
+}
+
+EAPI void
+ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_resize");
+ return;
+ }
+ if (ee->prop.fullscreen) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_resize) (ee, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_resize) (ee, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_move_resize");
+ return;
+ }
+ if (ee->prop.fullscreen) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_move_resize) (ee, x, y, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_move_resize) (ee, x, y, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_geometry_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (x) *x = ee->x;
+ if (y) *y = ee->y;
+ if (w) *w = ee->h;
+ if (h) *h = ee->w;
+ }
+ else
+ {
+ if (x) *x = ee->x;
+ if (y) *y = ee->y;
+ if (w) *w = ee->w;
+ if (h) *h = ee->h;
+ }
+}
+
+EAPI void
+ecore_evas_request_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_request_geometry_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (x) *x = ee->req.x;
+ if (y) *y = ee->req.y;
+ if (w) *w = ee->req.h;
+ if (h) *h = ee->req.w;
+ }
+ else
+ {
+ if (x) *x = ee->req.x;
+ if (y) *y = ee->req.y;
+ if (w) *w = ee->req.w;
+ if (h) *h = ee->req.h;
+ }
+}
+
+EAPI void
+ecore_evas_rotation_set(Ecore_Evas *ee, int rot)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_rotation_set");
+ return;
+ }
+ rot = rot % 360;
+ while (rot < 0) rot += 360;
+ while (rot >= 360) rot -= 360;
+ IFC(ee, fn_rotation_set) (ee, rot, 0);
+ /* make sure everything gets redrawn */
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ IFE;
+}
+
+EAPI void
+ecore_evas_rotation_with_resize_set(Ecore_Evas *ee, int rot)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_rotation_set");
+ return;
+ }
+ rot = rot % 360;
+ while (rot < 0) rot += 360;
+ while (rot >= 360) rot -= 360;
+ IFC(ee, fn_rotation_set) (ee, rot, 1);
+ /* make sure everything gets redrawn */
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ IFE;
+}
+
+EAPI int
+ecore_evas_rotation_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_rotation_get");
+ return 0;
+ }
+ return ee->rotation;
+}
+
+EAPI void
+ecore_evas_shaped_set(Ecore_Evas *ee, Eina_Bool shaped)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_shaped_set");
+ return;
+ }
+ IFC(ee, fn_shaped_set) (ee, shaped);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_shaped_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_shaped_get");
+ return EINA_FALSE;
+ }
+ return ee->shaped ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_alpha_set(Ecore_Evas *ee, Eina_Bool alpha)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_alpha_set");
+ return;
+ }
+ IFC(ee, fn_alpha_set) (ee, alpha);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_alpha_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_alpha_get");
+ return EINA_FALSE;
+ }
+ return ee->alpha ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_transparent_set(Ecore_Evas *ee, Eina_Bool transparent)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_transparent_set");
+ return;
+ }
+ IFC(ee, fn_transparent_set) (ee, transparent);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_transparent_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_transparent_get");
+ return EINA_FALSE;
+ }
+ return ee->transparent ? EINA_TRUE : 0;
+}
+
+EAPI void
+ecore_evas_show(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_show");
+ return;
+ }
+ IFC(ee, fn_show) (ee);
+ IFE;
+}
+
+EAPI void
+ecore_evas_hide(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_hide");
+ return;
+ }
+ IFC(ee, fn_hide) (ee);
+ IFE;
+}
+
+ EAPI int
+ecore_evas_visibility_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_visibility_get");
+ return 0;
+ }
+ return ee->visible ? 1:0;
+}
+
+EAPI void
+ecore_evas_raise(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_raise");
+ return;
+ }
+ IFC(ee, fn_raise) (ee);
+ IFE;
+}
+
+EAPI void
+ecore_evas_lower(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_lower");
+ return;
+ }
+ IFC(ee, fn_lower) (ee);
+ IFE;
+}
+
+EAPI void
+ecore_evas_activate(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_activate");
+ return;
+ }
+ IFC(ee, fn_activate) (ee);
+ IFE;
+}
+
+EAPI void
+ecore_evas_title_set(Ecore_Evas *ee, const char *t)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_title_set");
+ return;
+ }
+ IFC(ee, fn_title_set) (ee, t);
+ IFE;
+}
+
+EAPI const char *
+ecore_evas_title_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_title_get");
+ return NULL;
+ }
+ return ee->prop.title;
+}
+
+EAPI void
+ecore_evas_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_name_class_set");
+ return;
+ }
+ IFC(ee, fn_name_class_set) (ee, n, c);
+ IFE;
+}
+
+EAPI void
+ecore_evas_name_class_get(const Ecore_Evas *ee, const char **n, const char **c)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_name_class_get");
+ return;
+ }
+ if (n) *n = ee->prop.name;
+ if (c) *c = ee->prop.clas;
+}
+
+EAPI void
+ecore_evas_size_min_set(Ecore_Evas *ee, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_min_set");
+ return;
+ }
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_size_min_set) (ee, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_size_min_set) (ee, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_size_min_get(const Ecore_Evas *ee, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_min_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (w) *w = ee->prop.min.h;
+ if (h) *h = ee->prop.min.w;
+ }
+ else
+ {
+ if (w) *w = ee->prop.min.w;
+ if (h) *h = ee->prop.min.h;
+ }
+}
+
+EAPI void
+ecore_evas_size_max_set(Ecore_Evas *ee, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_max_set");
+ return;
+ }
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_size_max_set) (ee, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_size_max_set) (ee, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_size_max_get(const Ecore_Evas *ee, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_max_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (w) *w = ee->prop.max.h;
+ if (h) *h = ee->prop.max.w;
+ }
+ else
+ {
+ if (w) *w = ee->prop.max.w;
+ if (h) *h = ee->prop.max.h;
+ }
+}
+
+EAPI void
+ecore_evas_size_base_set(Ecore_Evas *ee, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_base_set");
+ return;
+ }
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_size_base_set) (ee, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_size_base_set) (ee, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_size_base_get(const Ecore_Evas *ee, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_base_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (w) *w = ee->prop.base.h;
+ if (h) *h = ee->prop.base.w;
+ }
+ else
+ {
+ if (w) *w = ee->prop.base.w;
+ if (h) *h = ee->prop.base.h;
+ }
+}
+
+EAPI void
+ecore_evas_size_step_set(Ecore_Evas *ee, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_step_set");
+ return;
+ }
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ IFC(ee, fn_size_step_set) (ee, h, w);
+ IFE;
+ }
+ else
+ {
+ IFC(ee, fn_size_step_set) (ee, w, h);
+ IFE;
+ }
+}
+
+EAPI void
+ecore_evas_size_step_get(const Ecore_Evas *ee, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_size_step_get");
+ return;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ if (w) *w = ee->prop.step.h;
+ if (h) *h = ee->prop.step.w;
+ }
+ else
+ {
+ if (w) *w = ee->prop.step.w;
+ if (h) *h = ee->prop.step.h;
+ }
+}
+
+EAPI void
+ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, int hot_y)
+{
+ Evas_Object *obj = NULL;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_cursor_set");
+ return;
+ }
+
+ if (file)
+ {
+ int x, y;
+
+ obj = evas_object_image_add(ee->evas);
+ evas_object_image_file_set(obj, file, NULL);
+ evas_object_image_size_get(obj, &x, &y);
+ evas_object_resize(obj, x, y);
+ evas_object_image_fill_set(obj, 0, 0, x, y);
+ }
+
+ IFC(ee, fn_object_cursor_set) (ee, obj, layer, hot_x, hot_y);
+ IFE;
+}
+
+EAPI void
+ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_cursor_set");
+ return;
+ }
+ IFC(ee, fn_object_cursor_set) (ee, obj, layer, hot_x, hot_y);
+ IFE;
+}
+
+EAPI void
+ecore_evas_cursor_get(const Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_cursor_get");
+ return;
+ }
+ if (obj) *obj = ee->prop.cursor.object;
+ if (layer) *layer = ee->prop.cursor.layer;
+ if (hot_x) *hot_x = ee->prop.cursor.hot.x;
+ if (hot_y) *hot_y = ee->prop.cursor.hot.y;
+}
+
+EAPI void
+ecore_evas_layer_set(Ecore_Evas *ee, int layer)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_layer_set");
+ return;
+ }
+ IFC(ee, fn_layer_set) (ee, layer);
+ IFE;
+}
+
+EAPI int
+ecore_evas_layer_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_layer_get");
+ return 0;
+ }
+ return ee->prop.layer;
+}
+
+EAPI void
+ecore_evas_focus_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_focus_set");
+ return;
+ }
+ IFC(ee, fn_focus_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_focus_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_focus_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.focused ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_iconified_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_iconified_set");
+ return;
+ }
+ IFC(ee, fn_iconified_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_iconified_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_iconified_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.iconified ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_borderless_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_borderless_set");
+ return;
+ }
+ IFC(ee, fn_borderless_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_borderless_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_borderless_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.borderless ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_override_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_override_set");
+ return;
+ }
+ IFC(ee, fn_override_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_override_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_override_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.override ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_maximized_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_maximized_set");
+ return;
+ }
+ IFC(ee, fn_maximized_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_maximized_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_maximized_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.maximized ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_fullscreen_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_fullscreen_set");
+ return;
+ }
+ IFC(ee, fn_fullscreen_set) (ee, on);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_fullscreen_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_fullscreen_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.fullscreen ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_avoid_damage_set(Ecore_Evas *ee, Ecore_Evas_Avoid_Damage_Type on)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_avoid_damage_set");
+ return;
+ }
+ IFC(ee, fn_avoid_damage_set) (ee, on);
+ IFE;
+}
+
+EAPI Ecore_Evas_Avoid_Damage_Type
+ecore_evas_avoid_damage_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_avoid_damage_get");
+ return ECORE_EVAS_AVOID_DAMAGE_NONE;
+ }
+ return ee->prop.avoid_damage;
+}
+
+EAPI void
+ecore_evas_withdrawn_set(Ecore_Evas *ee, Eina_Bool withdrawn)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_withdrawn_set");
+ return;
+ }
+
+ IFC(ee, fn_withdrawn_set) (ee, withdrawn);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_withdrawn_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_withdrawn_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.withdrawn ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_sticky_set(Ecore_Evas *ee, Eina_Bool sticky)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_sticky_set");
+ return;
+ }
+
+ IFC(ee, fn_sticky_set) (ee, sticky);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_sticky_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_sticky_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.sticky ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_window_group_set(Ecore_Evas *ee, const Ecore_Evas *ee_group)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_window_group_set) (ee, ee_group);
+ IFE;
+}
+
+EAPI const Ecore_Evas *
+ecore_evas_window_group_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.group_ee;
+}
+
+EAPI void
+ecore_evas_aspect_set(Ecore_Evas *ee, double aspect)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_aspect_set) (ee, aspect);
+ IFE;
+}
+
+EAPI double
+ecore_evas_aspect_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.aspect;
+}
+
+EAPI void
+ecore_evas_urgent_set(Ecore_Evas *ee, Eina_Bool urgent)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_urgent_set) (ee, urgent);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_urgent_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.urgent ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_modal_set(Ecore_Evas *ee, Eina_Bool modal)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_modal_set) (ee, modal);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_modal_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.modal ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_demand_attention_set(Ecore_Evas *ee, Eina_Bool demand)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_demands_attention_set) (ee, demand);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_demand_attention_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.demand_attention ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_focus_skip_set(Ecore_Evas *ee, Eina_Bool skip)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return;
+ }
+
+ IFC(ee, fn_focus_skip_set) (ee, skip);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_focus_skip_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "XXX");
+ return EINA_FALSE;
+ }
+ return ee->prop.focus_skip ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_ignore_events_set(Ecore_Evas *ee, Eina_Bool ignore)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_ignore_events_set");
+ return;
+ }
+
+ IFC(ee, fn_ignore_events_set) (ee, ignore);
+ IFE;
+}
+
+EAPI Eina_Bool
+ecore_evas_ignore_events_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_ignore_events_get");
+ return EINA_FALSE;
+ }
+ return ee->ignore_events ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_manual_render_set(Ecore_Evas *ee, Eina_Bool manual_render)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_manual_render_set");
+ return;
+ }
+ ee->manual_render = manual_render;
+}
+
+EAPI Eina_Bool
+ecore_evas_manual_render_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_manual_render_get");
+ return EINA_FALSE;
+ }
+ return ee->manual_render ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_evas_manual_render(Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_manual_render");
+ return;
+ }
+ if (ee->engine.func->fn_render)
+ ee->engine.func->fn_render(ee);
+}
+
+EAPI void
+ecore_evas_comp_sync_set(Ecore_Evas *ee, Eina_Bool do_sync)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_comp_sync_set");
+ return;
+ }
+ ee->no_comp_sync = !do_sync;
+}
+
+EAPI Eina_Bool
+ecore_evas_comp_sync_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_comp_sync_get");
+ return EINA_FALSE;
+ }
+ return !ee->no_comp_sync;
+}
+
+EAPI Ecore_Window
+ecore_evas_window_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_window_get");
+ return 0;
+ }
+
+ return ee->prop.window;
+}
+
+EAPI void
+ecore_evas_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
+{
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_screen_geometry_get");
+ return;
+ }
+
+ IFC(ee, fn_screen_geometry_get) (ee, x, y, w, h);
+ IFE;
+}
+
+EAPI void
+ecore_evas_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi)
+{
+ if (xdpi) *xdpi = 0;
+ if (ydpi) *ydpi = 0;
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_screen_geometry_get");
+ return;
+ }
+
+ IFC(ee, fn_screen_dpi_get) (ee, xdpi, ydpi);
+ IFE;
+}
+
+EAPI void
+ecore_evas_draw_frame_set(Ecore_Evas *ee, Eina_Bool draw_frame)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_draw_frame_set");
+ return;
+ }
+ ee->prop.draw_frame = draw_frame;
+}
+
+EAPI Eina_Bool
+ecore_evas_draw_frame_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_draw_frame_get");
+ return EINA_FALSE;
+ }
+ return ee->prop.draw_frame;
+}
+
+/* fps debug calls - for debugging how much time your app actually spends */
+/* rendering graphics... :) */
+
+static int _ecore_evas_fps_debug_init_count = 0;
+static int _ecore_evas_fps_debug_fd = -1;
+unsigned int *_ecore_evas_fps_rendertime_mmap = NULL;
+
+void
+_ecore_evas_fps_debug_init(void)
+{
+ char buf[4096];
+ const char *tmp;
+
+ _ecore_evas_fps_debug_init_count++;
+ if (_ecore_evas_fps_debug_init_count > 1) return;
+
+#ifndef HAVE_EVIL
+ tmp = "/tmp";
+#else
+ tmp = evil_tmpdir_get ();
+#endif /* HAVE_EVIL */
+ snprintf(buf, sizeof(buf), "%s/.ecore_evas_fps_debug-%i", tmp, (int)getpid());
+ _ecore_evas_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (_ecore_evas_fps_debug_fd < 0)
+ {
+ unlink(buf);
+ _ecore_evas_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ }
+ if (_ecore_evas_fps_debug_fd >= 0)
+ {
+ unsigned int zero = 0;
+ char *buf2 = (char *)&zero;
+ ssize_t todo = sizeof(unsigned int);
+
+ while (todo > 0)
+ {
+ ssize_t r = write(_ecore_evas_fps_debug_fd, buf2, todo);
+ if (r > 0)
+ {
+ todo -= r;
+ buf2 += r;
+ }
+ else if ((r < 0) && (errno == EINTR))
+ continue;
+ else
+ {
+ ERR("could not write to file '%s' fd %d: %s",
+ buf, _ecore_evas_fps_debug_fd, strerror(errno));
+ close(_ecore_evas_fps_debug_fd);
+ _ecore_evas_fps_debug_fd = -1;
+ return;
+ }
+ }
+ _ecore_evas_fps_rendertime_mmap = mmap(NULL, sizeof(unsigned int),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ _ecore_evas_fps_debug_fd, 0);
+ if (_ecore_evas_fps_rendertime_mmap == MAP_FAILED)
+ _ecore_evas_fps_rendertime_mmap = NULL;
+ }
+}
+
+void
+_ecore_evas_fps_debug_shutdown(void)
+{
+ _ecore_evas_fps_debug_init_count--;
+ if (_ecore_evas_fps_debug_init_count > 0) return;
+ if (_ecore_evas_fps_debug_fd >= 0)
+ {
+ char buf[4096];
+
+ snprintf(buf, sizeof(buf), "/tmp/.ecore_evas_fps_debug-%i", (int)getpid());
+ unlink(buf);
+ if (_ecore_evas_fps_rendertime_mmap)
+ {
+ munmap(_ecore_evas_fps_rendertime_mmap, sizeof(int));
+ _ecore_evas_fps_rendertime_mmap = NULL;
+ }
+ close(_ecore_evas_fps_debug_fd);
+ _ecore_evas_fps_debug_fd = -1;
+ }
+}
+
+void
+_ecore_evas_fps_debug_rendertime_add(double t)
+{
+ static double rtime = 0.0;
+ static double rlapse = 0.0;
+ static int frames = 0;
+ static int flapse = 0;
+ double tim;
+
+ tim = ecore_time_get();
+ rtime += t;
+ frames++;
+ if (rlapse == 0.0)
+ {
+ rlapse = tim;
+ flapse = frames;
+ }
+ else if ((tim - rlapse) >= 0.5)
+ {
+ printf("FRAME: %i, FPS: %3.1f, RTIME %3.0f%%\n",
+ frames,
+ (frames - flapse) / (tim - rlapse),
+ (100.0 * rtime) / (tim - rlapse)
+ );
+ rlapse = tim;
+ flapse = frames;
+ rtime = 0.0;
+ }
+}
+
+void
+_ecore_evas_register(Ecore_Evas *ee)
+{
+ ee->registered = 1;
+ ecore_evases = (Ecore_Evas *)eina_inlist_prepend
+ (EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee));
+}
+
+void
+_ecore_evas_ref(Ecore_Evas *ee)
+{
+ ee->refcount++;
+}
+
+void
+_ecore_evas_unref(Ecore_Evas *ee)
+{
+ ee->refcount--;
+ if (ee->refcount == 0)
+ {
+ if (ee->deleted) _ecore_evas_free(ee);
+ }
+ else if (ee->refcount < -1)
+ ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount);
+}
+
+void
+_ecore_evas_free(Ecore_Evas *ee)
+{
+ ee->deleted = EINA_TRUE;
+ if (ee->refcount > 0) return;
+
+ if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee);
+ while (ee->sub_ecore_evas)
+ {
+ _ecore_evas_free(ee->sub_ecore_evas->data);
+ }
+ if (ee->data) eina_hash_free(ee->data);
+ ee->data = NULL;
+ if (ee->name) free(ee->name);
+ ee->name = NULL;
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (ee->prop.name) free(ee->prop.name);
+ ee->prop.name = NULL;
+ if (ee->prop.clas) free(ee->prop.clas);
+ ee->prop.clas = NULL;
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+ ee->prop.cursor.object = NULL;
+ if (ee->evas) evas_free(ee->evas);
+ ee->evas = NULL;
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_NONE);
+ ee->driver = NULL;
+ if (ee->engine.idle_flush_timer)
+ ecore_timer_del(ee->engine.idle_flush_timer);
+ if (ee->engine.func->fn_free) ee->engine.func->fn_free(ee);
+ if (ee->registered)
+ {
+ ecore_evases = (Ecore_Evas *)eina_inlist_remove
+ (EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee));
+ }
+ free(ee);
+}
+
+static Eina_Bool
+_ecore_evas_cb_idle_flush(void *data)
+{
+ Ecore_Evas *ee;
+
+ ee = (Ecore_Evas *)data;
+ evas_render_idle_flush(ee->evas);
+ ee->engine.idle_flush_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_evas_async_events_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ evas_async_events_process();
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+void
+_ecore_evas_idle_timeout_update(Ecore_Evas *ee)
+{
+ if (ee->engine.idle_flush_timer)
+ ecore_timer_del(ee->engine.idle_flush_timer);
+ ee->engine.idle_flush_timer = ecore_timer_add(IDLE_FLUSH_TIME,
+ _ecore_evas_cb_idle_flush,
+ ee);
+}
+
+void
+_ecore_evas_mouse_move_process(Ecore_Evas *ee, int x, int y, unsigned int timestamp)
+{
+ ee->mouse.x = x;
+ ee->mouse.y = y;
+ if (ee->prop.cursor.object)
+ {
+ int fx, fy;
+ evas_output_framespace_get(ee->evas, &fx, &fy, NULL, NULL);
+ evas_object_show(ee->prop.cursor.object);
+ if (ee->rotation == 0)
+ evas_object_move(ee->prop.cursor.object,
+ x - fx - ee->prop.cursor.hot.x,
+ y - fy - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 90)
+ evas_object_move(ee->prop.cursor.object,
+ ee->h - y - fx - 1 - ee->prop.cursor.hot.x,
+ x - fy - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 180)
+ evas_object_move(ee->prop.cursor.object,
+ ee->w - x - fx - 1 - ee->prop.cursor.hot.x,
+ ee->h - y - fy - 1 - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 270)
+ evas_object_move(ee->prop.cursor.object,
+ y - fx - ee->prop.cursor.hot.x,
+ ee->w - x - fy - 1 - ee->prop.cursor.hot.y);
+ }
+ if (ee->rotation == 0)
+ evas_event_feed_mouse_move(ee->evas, x, y, timestamp, NULL);
+ else if (ee->rotation == 90)
+ evas_event_feed_mouse_move(ee->evas, ee->h - y - 1, x, timestamp, NULL);
+ else if (ee->rotation == 180)
+ evas_event_feed_mouse_move(ee->evas, ee->w - x - 1, ee->h - y - 1, timestamp, NULL);
+ else if (ee->rotation == 270)
+ evas_event_feed_mouse_move(ee->evas, y, ee->w - x - 1, timestamp, NULL);
+}
+
+void
+_ecore_evas_mouse_multi_move_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ unsigned int timestamp)
+{
+ if (ee->rotation == 0)
+ evas_event_feed_multi_move(ee->evas, device,
+ x, y,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ mx, my,
+ timestamp, NULL);
+ else if (ee->rotation == 90)
+ evas_event_feed_multi_move(ee->evas, device,
+ ee->h - y - 1, x,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ ee->h - my - 1, mx,
+ timestamp, NULL);
+ else if (ee->rotation == 180)
+ evas_event_feed_multi_move(ee->evas, device,
+ ee->w - x - 1, ee->h - y - 1,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ ee->w - mx - 1, ee->h - my - 1,
+ timestamp, NULL);
+ else if (ee->rotation == 270)
+ evas_event_feed_multi_move(ee->evas, device,
+ y, ee->w - x - 1,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ my, ee->w - mx - 1,
+ timestamp, NULL);
+}
+
+void
+_ecore_evas_mouse_multi_down_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ Evas_Button_Flags flags,
+ unsigned int timestamp)
+{
+ if (ee->rotation == 0)
+ evas_event_feed_multi_down(ee->evas, device,
+ x, y,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ mx, my,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 90)
+ evas_event_feed_multi_down(ee->evas, device,
+ ee->h - y - 1, x,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ ee->h - my - 1, mx,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 180)
+ evas_event_feed_multi_down(ee->evas, device,
+ ee->w - x - 1, ee->h - y - 1,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ ee->w - mx - 1, ee->h - my - 1,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 270)
+ evas_event_feed_multi_down(ee->evas, device,
+ y, ee->w - x - 1,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ my, ee->w - mx - 1,
+ flags, timestamp, NULL);
+}
+
+void
+_ecore_evas_mouse_multi_up_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ Evas_Button_Flags flags,
+ unsigned int timestamp)
+{
+ if (ee->rotation == 0)
+ evas_event_feed_multi_up(ee->evas, device,
+ x, y,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ mx, my,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 90)
+ evas_event_feed_multi_up(ee->evas, device,
+ ee->h - y - 1, x,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ ee->h - my - 1, mx,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 180)
+ evas_event_feed_multi_up(ee->evas, device,
+ ee->w - x - 1, ee->h - y - 1,
+ radius,
+ radius_x, radius_y,
+ pressure,
+ angle - ee->rotation,
+ ee->w - mx - 1, ee->h - my - 1,
+ flags, timestamp, NULL);
+ else if (ee->rotation == 270)
+ evas_event_feed_multi_up(ee->evas, device,
+ y, ee->w - x - 1,
+ radius,
+ radius_y, radius_x,
+ pressure,
+ angle - ee->rotation,
+ my, ee->w - mx - 1,
+ flags, timestamp, NULL);
+}
+
+EAPI Eina_List *
+ecore_evas_ecore_evas_list_get(void)
+{
+ Ecore_Evas *ee;
+ Eina_List *l = NULL;
+
+ EINA_INLIST_FOREACH(ecore_evases, ee)
+ {
+ l = eina_list_append(l, ee);
+ }
+
+ return l;
+}
+
+EAPI void
+ecore_evas_input_event_register(Ecore_Evas *ee)
+{
+ ecore_event_window_register((Ecore_Window)ee, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+}
+
+EAPI void
+ecore_evas_input_event_unregister(Ecore_Evas *ee)
+{
+ ecore_event_window_unregister((Ecore_Window)ee);
+}
+
+#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined (BUILD_ECORE_EVAS_WAYLAND_EGL)
+EAPI void
+ecore_evas_wayland_resize(Ecore_Evas *ee, int location)
+{
+ if (!ee) return;
+ if (!strcmp(ee->driver, "wayland_shm"))
+ {
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+ _ecore_evas_wayland_shm_resize(ee, location);
+#endif
+ }
+ else if (!strcmp(ee->driver, "wayland_egl"))
+ {
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+ _ecore_evas_wayland_egl_resize(ee, location);
+#endif
+ }
+}
+
+EAPI void
+ecore_evas_wayland_move(Ecore_Evas *ee, int x, int y)
+{
+ if (!ee) return;
+ if (!strncmp(ee->driver, "wayland", 7))
+ {
+ if (ee->engine.wl.win)
+ {
+ ee->engine.wl.win->moving = EINA_TRUE;
+ ecore_wl_window_move(ee->engine.wl.win, x, y);
+ }
+ }
+}
+
+EAPI void
+ecore_evas_wayland_type_set(Ecore_Evas *ee, int type)
+{
+ if (!ee) return;
+ ecore_wl_window_type_set(ee->engine.wl.win, type);
+}
+
+EAPI Ecore_Wl_Window *
+ecore_evas_wayland_window_get(const Ecore_Evas *ee)
+{
+ if (!(!strncmp(ee->driver, "wayland", 7)))
+ return NULL;
+
+ return ee->engine.wl.win;
+}
+
+EAPI void
+ecore_evas_wayland_pointer_set(Ecore_Evas *ee EINA_UNUSED, int hot_x EINA_UNUSED, int hot_y EINA_UNUSED)
+{
+
+}
+
+#else
+EAPI void
+ecore_evas_wayland_resize(Ecore_Evas *ee EINA_UNUSED, int location EINA_UNUSED)
+{
+
+}
+
+EAPI void
+ecore_evas_wayland_move(Ecore_Evas *ee EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED)
+{
+
+}
+
+EAPI void
+ecore_evas_wayland_type_set(Ecore_Evas *ee EINA_UNUSED, int type EINA_UNUSED)
+{
+
+}
+
+EAPI Ecore_Wl_Window *
+ecore_evas_wayland_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI void
+ecore_evas_wayland_pointer_set(Ecore_Evas *ee EINA_UNUSED, int hot_x EINA_UNUSED, int hot_y EINA_UNUSED)
+{
+
+}
+
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_buffer.c b/src/lib/ecore_evas/ecore_evas_buffer.c
new file mode 100644
index 0000000000..26f48ce336
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_buffer.c
@@ -0,0 +1,836 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar!
+#include <stdlib.h>
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#include <Ecore_Input.h>
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+static int _ecore_evas_init_count = 0;
+
+static int
+_ecore_evas_buffer_init(void)
+{
+ _ecore_evas_init_count++;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_buffer_free(Ecore_Evas *ee)
+{
+ if (ee->engine.buffer.image)
+ {
+ Ecore_Evas *ee2;
+
+ ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent");
+ evas_object_del(ee->engine.buffer.image);
+ ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee);
+ }
+ else
+ {
+ ee->engine.buffer.free_func(ee->engine.buffer.data,
+ ee->engine.buffer.pixels);
+ }
+ _ecore_evas_buffer_shutdown();
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ Evas_Engine_Info_Buffer *einfo;
+ int stride = 0;
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ if (ee->engine.buffer.image)
+ {
+ ee->engine.buffer.pixels = evas_object_image_data_get(ee->engine.buffer.image, 1);
+ stride = evas_object_image_stride_get(ee->engine.buffer.image);
+ }
+ else
+ {
+ if (ee->engine.buffer.pixels)
+ ee->engine.buffer.free_func(ee->engine.buffer.data,
+ ee->engine.buffer.pixels);
+ ee->engine.buffer.pixels =
+ ee->engine.buffer.alloc_func(ee->engine.buffer.data,
+ ee->w * ee->h * sizeof(int));
+ stride = ee->w * sizeof(int);
+ }
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->alpha)
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ else
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.dest_buffer = ee->engine.buffer.pixels;
+ einfo->info.dest_buffer_row_bytes = stride;
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+ if (ee->engine.buffer.image)
+ evas_object_image_data_set(ee->engine.buffer.image, ee->engine.buffer.pixels);
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ _ecore_evas_resize(ee, w, h);
+}
+
+int
+_ecore_evas_buffer_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_show(Ecore_Evas *ee)
+{
+ if (ee->engine.buffer.image) return;
+ if (ee->prop.focused) return;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+}
+
+int
+_ecore_evas_buffer_render(Ecore_Evas *ee)
+{
+ Eina_List *updates = NULL, *l, *ll;
+ Ecore_Evas *ee2;
+ int rend = 0;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+ if (ee->engine.buffer.image)
+ {
+ int w, h;
+
+ evas_object_image_size_get(ee->engine.buffer.image, &w, &h);
+ if ((w != ee->w) || (h != ee->h))
+ _ecore_evas_resize(ee, w, h);
+ ee->engine.buffer.pixels = evas_object_image_data_get(ee->engine.buffer.image, 1);
+ }
+ if (ee->engine.buffer.pixels)
+ {
+ updates = evas_render_updates(ee->evas);
+ }
+ if (ee->engine.buffer.image)
+ {
+ Eina_Rectangle *r;
+
+ evas_object_image_data_set(ee->engine.buffer.image, ee->engine.buffer.pixels);
+ EINA_LIST_FOREACH(updates, l, r)
+ evas_object_image_data_update_add(ee->engine.buffer.image,
+ r->x, r->y, r->w, r->h);
+ }
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ }
+
+ return updates ? 1 : rend;
+}
+
+// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar!
+static void
+_ecore_evas_buffer_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
+{
+ Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh;
+
+ evas_object_geometry_get(ee->engine.buffer.image, &xx, &yy, &ww, &hh);
+ evas_object_image_fill_get(ee->engine.buffer.image, &fx, &fy, &fw, &fh);
+
+ if (fw < 1) fw = 1;
+ if (fh < 1) fh = 1;
+
+ if (evas_object_map_get(ee->engine.buffer.image) &&
+ evas_object_map_enable_get(ee->engine.buffer.image))
+ {
+ fx = 0; fy = 0;
+ fw = ee->w; fh = ee->h;
+ ww = ee->w; hh = ee->h;
+ }
+
+ if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh))
+ {
+ *x = (ee->w * (*x - xx)) / fw;
+ *y = (ee->h * (*y - yy)) / fh;
+ }
+ else
+ {
+ xx = (*x - xx) - fx;
+ while (xx < 0) xx += fw;
+ while (xx > fw) xx -= fw;
+ *x = (ee->w * xx) / fw;
+
+ yy = (*y - yy) - fy;
+ while (yy < 0) yy += fh;
+ while (yy > fh) yy -= fh;
+ *y = (ee->h * yy) / fh;
+ }
+}
+
+static void
+_ecore_evas_buffer_transfer_modifiers_locks(Evas *e, Evas *e2)
+{
+ const char *mods[] =
+ { "Shift", "Control", "Alt", "Meta", "Hyper", "Super", NULL };
+ const char *locks[] =
+ { "Scroll_Lock", "Num_Lock", "Caps_Lock", NULL };
+ int i;
+
+ for (i = 0; mods[i]; i++)
+ {
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), mods[i]))
+ evas_key_modifier_on(e2, mods[i]);
+ else
+ evas_key_modifier_off(e2, mods[i]);
+ }
+ for (i = 0; locks[i]; i++)
+ {
+ if (evas_key_lock_is_set(evas_key_lock_get(e), locks[i]))
+ evas_key_lock_on(e2, locks[i]);
+ else
+ evas_key_lock_off(e2, locks[i]);
+ }
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_in(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_In *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_out(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_Out *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_Down *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_mouse_down(ee->evas, ev->button, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_up(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_Up *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_mouse_up(ee->evas, ev->button, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_move(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_Move *ev;
+ Evas_Coord x, y;
+
+ ee = data;
+ ev = event_info;
+ x = ev->cur.canvas.x;
+ y = ev->cur.canvas.y;
+ _ecore_evas_buffer_coord_translate(ee, &x, &y);
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp);
+}
+
+static void
+_ecore_evas_buffer_cb_mouse_wheel(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Mouse_Wheel *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_mouse_wheel(ee->evas, ev->direction, ev->z, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_multi_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Multi_Down *ev;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ ee = data;
+ ev = event_info;
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_buffer_coord_translate(ee, &x, &y);
+ xf = (ev->canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_multi_down(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_multi_up(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Multi_Up *ev;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ ee = data;
+ ev = event_info;
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_buffer_coord_translate(ee, &x, &y);
+ xf = (ev->canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_multi_up(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_multi_move(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Multi_Move *ev;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ ee = data;
+ ev = event_info;
+ x = ev->cur.canvas.x;
+ y = ev->cur.canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_buffer_coord_translate(ee, &x, &y);
+ xf = (ev->cur.canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->cur.canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_multi_move(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_free(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee->driver) _ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_buffer_cb_key_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Key_Down *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_key_down(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_key_up(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee;
+ Evas_Event_Key_Up *ev;
+
+ ee = data;
+ ev = event_info;
+ _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas);
+ evas_event_feed_key_up(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_buffer_cb_focus_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+}
+
+static void
+_ecore_evas_buffer_cb_focus_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ ee->prop.focused = 0;
+ evas_focus_out(ee->evas);
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+}
+
+static void
+_ecore_evas_buffer_cb_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+}
+
+static void
+_ecore_evas_buffer_cb_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ ee->visible = 0;
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+}
+
+static void
+_ecore_evas_buffer_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha))) return;
+ ee->alpha = alpha;
+ if (ee->engine.buffer.image)
+ evas_object_image_alpha_set(ee->engine.buffer.image, ee->alpha);
+ else
+ {
+ Evas_Engine_Info_Buffer *einfo;
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->alpha)
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ else
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ }
+ }
+}
+
+static Ecore_Evas_Engine_Func _ecore_buffer_engine_func =
+{
+ _ecore_evas_buffer_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ NULL,
+ NULL,
+ _ecore_evas_show,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_buffer_alpha_set,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ _ecore_evas_buffer_render,
+ NULL, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+#endif
+
+static void *
+_ecore_evas_buffer_pix_alloc(void *data EINA_UNUSED, int size)
+{
+ return malloc(size);
+}
+
+static void
+_ecore_evas_buffer_pix_free(void *data EINA_UNUSED, void *pix)
+{
+ free(pix);
+}
+
+EAPI Ecore_Evas *
+ecore_evas_buffer_new(int w, int h)
+{
+ return ecore_evas_buffer_allocfunc_new
+ (w, h, _ecore_evas_buffer_pix_alloc, _ecore_evas_buffer_pix_free, NULL);
+}
+
+EAPI Ecore_Evas *
+ecore_evas_buffer_allocfunc_new(int w, int h, void *(*alloc_func) (void *data, int size), void (*free_func) (void *data, void *pix), const void *data)
+{
+// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar!
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ Evas_Engine_Info_Buffer *einfo;
+ Ecore_Evas *ee;
+ int rmethod;
+
+ if ((!alloc_func) || (!free_func)) return NULL;
+ rmethod = evas_render_method_lookup("buffer");
+ if (!rmethod) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_buffer_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_buffer_engine_func;
+ ee->engine.buffer.alloc_func = alloc_func;
+ ee->engine.buffer.free_func = free_func;
+ ee->engine.buffer.data = (void *)data;
+
+ ee->driver = "buffer";
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->rotation = 0;
+ ee->visible = 1;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 1;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 1;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ ee->engine.buffer.pixels =
+ ee->engine.buffer.alloc_func
+ (ee->engine.buffer.data, w * h * sizeof(int));
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.dest_buffer = ee->engine.buffer.pixels;
+ einfo->info.dest_buffer_row_bytes = ee->w * sizeof(int);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ evas_key_modifier_add(ee->evas, "Shift");
+ evas_key_modifier_add(ee->evas, "Control");
+ evas_key_modifier_add(ee->evas, "Alt");
+ evas_key_modifier_add(ee->evas, "Meta");
+ evas_key_modifier_add(ee->evas, "Hyper");
+ evas_key_modifier_add(ee->evas, "Super");
+ evas_key_lock_add(ee->evas, "Caps_Lock");
+ evas_key_lock_add(ee->evas, "Num_Lock");
+ evas_key_lock_add(ee->evas, "Scroll_Lock");
+
+ evas_event_feed_mouse_in(ee->evas, 0, NULL);
+
+ _ecore_evas_register(ee);
+
+ evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
+
+ return ee;
+#else
+ return NULL;
+#endif
+}
+
+EAPI const void *
+ecore_evas_buffer_pixels_get(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ if (!ee)
+ {
+ CRIT("Ecore_Evas is missing");
+ return NULL;
+ }
+ _ecore_evas_buffer_render(ee);
+ return ee->engine.buffer.pixels;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Evas *
+ecore_evas_object_evas_get(Evas_Object *obj)
+{
+ Ecore_Evas *ee;
+
+ ee = evas_object_data_get(obj, "Ecore_Evas");
+ if (!ee) return NULL;
+
+ return ecore_evas_get(ee);
+}
+
+EAPI Ecore_Evas *
+ecore_evas_object_ecore_evas_get(Evas_Object *obj)
+{
+ return evas_object_data_get(obj, "Ecore_Evas");
+}
+
+EAPI Evas_Object *
+ecore_evas_object_image_new(Ecore_Evas *ee_target)
+{
+// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar!
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ Evas_Object *o;
+ Evas_Engine_Info_Buffer *einfo;
+ Ecore_Evas *ee;
+ int rmethod;
+ int w = 1, h = 1;
+
+ if (!ee_target) return NULL;
+
+ rmethod = evas_render_method_lookup("buffer");
+ if (!rmethod) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ o = evas_object_image_add(ee_target->evas);
+ evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
+ evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(o, 0);
+ evas_object_image_size_set(o, w, h);
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_buffer_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_buffer_engine_func;
+
+ ee->driver = "buffer";
+
+ ee->rotation = 0;
+ ee->visible = 0;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 0;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 0;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ ee->engine.buffer.image = o;
+ evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas", ee);
+ evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas_Parent", ee_target);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_IN,
+ _ecore_evas_buffer_cb_mouse_in, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_OUT,
+ _ecore_evas_buffer_cb_mouse_out, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_DOWN,
+ _ecore_evas_buffer_cb_mouse_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_UP,
+ _ecore_evas_buffer_cb_mouse_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_MOVE,
+ _ecore_evas_buffer_cb_mouse_move, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_WHEEL,
+ _ecore_evas_buffer_cb_mouse_wheel, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_DOWN,
+ _ecore_evas_buffer_cb_multi_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_UP,
+ _ecore_evas_buffer_cb_multi_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_MOVE,
+ _ecore_evas_buffer_cb_multi_move, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FREE,
+ _ecore_evas_buffer_cb_free, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_KEY_DOWN,
+ _ecore_evas_buffer_cb_key_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_KEY_UP,
+ _ecore_evas_buffer_cb_key_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FOCUS_IN,
+ _ecore_evas_buffer_cb_focus_in, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FOCUS_OUT,
+ _ecore_evas_buffer_cb_focus_out, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_SHOW,
+ _ecore_evas_buffer_cb_show, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_HIDE,
+ _ecore_evas_buffer_cb_hide, ee);
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ ee->engine.buffer.pixels = evas_object_image_data_get(o, 1);
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ einfo->info.dest_buffer = ee->engine.buffer.pixels;
+ einfo->info.dest_buffer_row_bytes = evas_object_image_stride_get(o);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ evas_object_image_data_set(o, ee->engine.buffer.pixels);
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ evas_key_modifier_add(ee->evas, "Shift");
+ evas_key_modifier_add(ee->evas, "Control");
+ evas_key_modifier_add(ee->evas, "Alt");
+ evas_key_modifier_add(ee->evas, "Meta");
+ evas_key_modifier_add(ee->evas, "Hyper");
+ evas_key_modifier_add(ee->evas, "Super");
+ evas_key_lock_add(ee->evas, "Caps_Lock");
+ evas_key_lock_add(ee->evas, "Num_Lock");
+ evas_key_lock_add(ee->evas, "Scroll_Lock");
+
+ ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee);
+
+ return o;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/lib/ecore_evas/ecore_evas_cocoa.c b/src/lib/ecore_evas/ecore_evas_cocoa.c
new file mode 100644
index 0000000000..bf88e5e33f
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_cocoa.c
@@ -0,0 +1,584 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Input.h"
+#include "Ecore_Input_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+#include <Ecore_Cocoa.h>
+#include <Evas_Engine_GL_Cocoa.h>
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+
+// FIXME: this engine has lots of problems. only 1 window at a time, drawRect looks wrong, doesnt handle resizes and more
+
+static int _ecore_evas_init_count = 0;
+static Ecore_Evas *ecore_evases = NULL;
+static Ecore_Event_Handler *ecore_evas_event_handlers[4] = {
+ NULL, NULL, NULL, NULL
+};
+static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL;
+static Ecore_Poller *ecore_evas_event = NULL;
+
+static const char *ecore_evas_cocoa_default = "EFL Cocoa";
+
+
+static int
+_ecore_evas_cocoa_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *updates = NULL;
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ DBG("Render");
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+ updates = evas_render_updates(ee->evas);
+ if (ee->prop.avoid_damage)
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ else if ((ee->visible) ||
+ ((ee->should_be_visible) && (ee->prop.fullscreen)) ||
+ ((ee->should_be_visible) && (ee->prop.override)))
+ {
+ if (ee->shaped)
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ else
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ }
+ else
+ evas_norender(ee->evas);
+ if (updates) rend = 1;
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+
+ if (rend)
+ {
+ static int frames = 0;
+ static double t0 = 0.0;
+ double t, td;
+
+ t = ecore_time_get();
+ frames++;
+ if ((t - t0) > 1.0)
+ {
+ td = t - t0;
+ printf("FPS: %3.3f\n", (double)frames / td);
+ frames = 0;
+ t0 = t;
+ }
+ }
+
+ return rend;
+}
+
+
+static Ecore_Evas *
+_ecore_evas_cocoa_match(void)
+{
+ DBG("Match");
+ return ecore_evases;
+}
+
+static int
+_ecore_evas_cocoa_event_got_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+
+ DBG("Got Focus");
+
+ ee = _ecore_evas_cocoa_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_cocoa_event_lost_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+
+ DBG("Lost Focus");
+
+ ee = _ecore_evas_cocoa_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ evas_focus_out(ee->evas);
+ ee->prop.focused = 0;
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_cocoa_event_video_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ /*Ecore_Cocoa_Event_Video_Resize *e;
+ Ecore_Evas *ee;
+
+ e = event;
+ ee = _ecore_evas_cocoa_match();
+
+ if (!ee) return 1; // pass on event
+ evas_output_size_set(ee->evas, e->w, e->h);
+
+ return 0;*/
+
+ DBG("Video Resize");
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_cocoa_event_video_expose(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ int w;
+ int h;
+
+ DBG("Video Expose");
+
+ ee = _ecore_evas_cocoa_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ evas_output_size_get(ee->evas, &w, &h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, w, h);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_idle_enter(void *data EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ double t1 = 0.;
+ double t2 = 0.;
+
+ DBG("Idle enter");
+
+ EINA_INLIST_FOREACH(ecore_evases, ee)
+ {
+ if (ee->visible)
+ evas_render(ee->evas);
+ else
+ evas_norender(ee->evas);
+ }
+
+ return EINA_TRUE;
+}
+
+static int
+_ecore_evas_cocoa_event(void *data)
+{
+ // ecore_cocoa_feed_events();
+
+ DBG("Cocoa Event");
+
+ return 1;
+}
+
+static int
+_ecore_evas_cocoa_init(void)
+{
+ DBG("Cocoa Init");
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1)
+ return _ecore_evas_init_count;
+
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_COCOA_EVENT_GOT_FOCUS, _ecore_evas_cocoa_event_got_focus, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_COCOA_EVENT_LOST_FOCUS, _ecore_evas_cocoa_event_lost_focus, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_COCOA_EVENT_RESIZE, _ecore_evas_cocoa_event_video_resize, NULL);
+ ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_COCOA_EVENT_EXPOSE, _ecore_evas_cocoa_event_video_expose, NULL);
+
+ ecore_event_evas_init();
+ return _ecore_evas_init_count;
+}
+
+static int
+_ecore_evas_cocoa_shutdown(void)
+{
+ DBG("Cocoa SHutodwn");
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ int i;
+
+ while (ecore_evases) _ecore_evas_free(ecore_evases);
+
+ for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler*); i++)
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ ecore_event_evas_shutdown();
+ ecore_idle_enterer_del(ecore_evas_idle_enterer);
+ ecore_evas_idle_enterer = NULL;
+ ecore_poller_del(ecore_evas_event);
+ ecore_evas_event = NULL;
+
+ ecore_event_evas_shutdown();
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_cocoa_free(Ecore_Evas *ee)
+{
+ DBG("Cocoa Free");
+ ecore_evases = (Ecore_Evas *) eina_inlist_remove(EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee));
+ ecore_event_window_unregister(0);
+ _ecore_evas_cocoa_shutdown();
+ ecore_cocoa_shutdown();
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ DBG("Resize");
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+
+ printf("Ecore_Evas Resize %d %d\n", w, h);
+
+ ecore_cocoa_window_resize(ee->prop.window, w, h);
+
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ DBG("Move Resize");
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+
+ ecore_cocoa_window_move_resize(ee->prop.window, x, y, w, h);
+
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+
+static void
+_ecore_evas_show(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ DBG("Show");
+ ee->should_be_visible = 1;
+ if (ee->prop.avoid_damage)
+ _ecore_evas_cocoa_render(ee);
+
+ ecore_cocoa_window_show(ee->prop.window);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+}
+
+
+static void
+_ecore_evas_hide(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ DBG("Hide");
+
+ ecore_cocoa_window_hide(ee->prop.window);
+ ee->should_be_visible = 0;
+}
+
+static void
+_ecore_evas_title_set(Ecore_Evas *ee, const char *title)
+{
+ INF("ecore evas title set");
+
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (title) ee->prop.title = strdup(title);
+ ecore_cocoa_window_title_set(ee->prop.window,
+ ee->prop.title);
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Ecore_Evas *ee;
+
+ DBG("Cursor DEL");
+
+ ee = data;
+ if (ee)
+ ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+ DBG("Cursor Set");
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (obj == NULL)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+static int
+_ecore_evas_engine_cocoa_init(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_GL_Cocoa *einfo;
+ const char *driver;
+ int rmethod;
+
+ DBG("Cocoa Init");
+
+ driver = "gl_cocoa";
+
+ rmethod = evas_render_method_lookup(driver);
+ if (!rmethod)
+ return 0;
+
+ ee->driver = driver;
+ evas_output_method_set(ee->evas, rmethod);
+
+ einfo = (Evas_Engine_Info_GL_Cocoa *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ /* FIXME: REDRAW_DEBUG missing for now */
+ einfo->window = ee->prop.window;
+ //einfo->info.depth = ecore_win32_screen_depth_get();
+ //einfo->info.rotation = 0;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ ecore_cocoa_window_view_set(einfo->window, einfo->view);
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ return 0;
+ }
+
+ return 1;
+}
+
+static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func =
+ {
+ _ecore_evas_cocoa_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //move
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ NULL, //rotation
+ NULL, //shaped
+ _ecore_evas_show,
+ _ecore_evas_hide,
+ NULL, //raise
+ NULL, //lower
+ NULL, //activate
+ _ecore_evas_title_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_object_cursor_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL,
+ NULL // screen_dpi_get
+ };
+#endif
+
+EAPI Ecore_Evas *
+ecore_evas_cocoa_new(Ecore_Cocoa_Window *parent, int x, int y, int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA
+ Evas_Engine_Info_GL_Cocoa *einfo;
+ Ecore_Evas *ee;
+ int rmethod;
+
+ DBG("Cocoa new");
+
+ if (!ecore_cocoa_init())
+ return NULL;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee)
+ goto shutdown_ecore_cocoa;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_cocoa_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_cocoa_engine_func;
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->visible = 1;
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->semi_sync = 1;
+
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->prop.window = 0;
+
+ printf("Create New Evas\n");
+
+ ee->evas = evas_new();
+
+ if (!ee->evas)
+ goto free_name;
+
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ printf("Create New Cocoa Window\n");
+ ee->prop.window = (Ecore_Cocoa_Window*)ecore_cocoa_window_new(x, y, w, h);
+ printf("Window Created %p\n", ee->prop.window);
+ if (!ee->prop.window)
+ {
+ _ecore_evas_cocoa_shutdown();
+ free(ee);
+ return NULL;
+ }
+
+ printf("Init Evas engine cocoa\n");
+ if (!_ecore_evas_engine_cocoa_init(ee))
+ {
+ _ecore_evas_cocoa_shutdown();
+ free(ee);
+ return NULL;
+ }
+
+
+ ee->engine.func->fn_render = _ecore_evas_cocoa_render;
+ _ecore_evas_register(ee);
+ ecore_event_window_register(0, ee, ee->evas, NULL, NULL, NULL, NULL);
+
+ evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
+ printf("Ecore Evas returned : %p\n", ee);
+ return ee;
+
+ free_window:
+ /* FIXME: free window here */
+ free_evas:
+ free(ee->evas);
+ free_name:
+ free(ee->name);
+ free_ee:
+ _ecore_evas_cocoa_shutdown();
+ free(ee);
+ shutdown_ecore_cocoa:
+ ecore_cocoa_shutdown();
+
+ return NULL;
+#else
+ ERR("Cocoa support in ecore-evas not enabled");
+ return NULL;
+ (void) parent;
+ (void) x; (void) y; (void) w; (void) h;
+#endif
+}
diff --git a/src/lib/ecore_evas/ecore_evas_directfb.c b/src/lib/ecore_evas/ecore_evas_directfb.c
new file mode 100644
index 0000000000..f3567341b1
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_directfb.c
@@ -0,0 +1,606 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+#include <Ecore_DirectFB.h>
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+static int _ecore_evas_init_count = 0;
+static Ecore_Event_Handler *ecore_evas_event_handlers[13];
+
+static Eina_Hash *ecore_evases_hash = NULL;
+
+static int
+_ecore_evas_directfb_render(Ecore_Evas *ee)
+{
+ Eina_List *updates, *ll;
+ Ecore_Evas *ee2;
+ int rend = 0;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+ updates = evas_render_updates(ee->evas);
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ }
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+
+ return updates ? 1 : rend;
+}
+
+static char *
+_ecore_evas_directfb_winid_str_get(Ecore_X_Window win)
+{
+ const char *vals = "qWeRtYuIoP5$&<~";
+ static char id[9];
+ unsigned int val;
+ val = (unsigned int)win;
+ id[0] = vals[(val >> 28) & 0xf];
+ id[1] = vals[(val >> 24) & 0xf];
+ id[2] = vals[(val >> 20) & 0xf];
+ id[3] = vals[(val >> 16) & 0xf];
+ id[4] = vals[(val >> 12) & 0xf];
+ id[5] = vals[(val >> 8) & 0xf];
+ id[6] = vals[(val >> 4) & 0xf];
+ id[7] = vals[(val ) & 0xf];
+ id[8] = 0;
+ return id;
+}
+
+static Ecore_Evas *
+_ecore_evas_directfb_match(DFBWindowID win)
+{
+ Ecore_Evas *ee;
+
+ ee = eina_hash_find(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(win));
+ return ee;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Key_Down *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ evas_event_feed_key_down(ee->evas, e->name, e->name, e->string,
+ e->key_compose, e->time, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_key_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Key_Up *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ evas_event_feed_key_up(ee->evas, e->name, e->name, e->string,
+ e->key_compose, e->time, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_motion(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Motion *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_button_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Button_Down *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ // _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ evas_event_feed_mouse_down(ee->evas, e->button, EVAS_BUTTON_NONE, e->time, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_button_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Button_Up *e;
+ Evas_Button_Flags flags = EVAS_BUTTON_NONE;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_enter(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Enter *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ evas_event_feed_mouse_in(ee->evas, e->time, NULL);
+ //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_leave(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Leave *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ evas_event_feed_mouse_out(ee->evas, e->time, NULL);
+ //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Wheel *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ evas_event_feed_mouse_wheel(ee->evas, e->direction, e->z, e->time, NULL);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_got_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Got_Focus *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ ee->prop.focused = 1;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_evas_directfb_event_lost_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Event_Lost_Focus *e;
+
+ e = event;
+ ee = _ecore_evas_directfb_match(e->win);
+
+ if (!ee) return EINA_TRUE; /* pass on event */
+ ee->prop.focused = 0;
+ return EINA_TRUE;
+}
+
+int
+_ecore_evas_directfb_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+
+
+
+
+int
+_ecore_evas_directfb_init(void)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_KEY_DOWN, _ecore_evas_directfb_event_key_down, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_KEY_UP, _ecore_evas_directfb_event_key_up, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_BUTTON_DOWN, _ecore_evas_directfb_event_button_down, NULL);
+ ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_BUTTON_UP, _ecore_evas_directfb_event_button_up, NULL);
+ ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_MOTION, _ecore_evas_directfb_event_motion, NULL);
+ ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_ENTER, _ecore_evas_directfb_event_enter, NULL);
+ ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_LEAVE, _ecore_evas_directfb_event_leave, NULL);
+ ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_WHEEL, _ecore_evas_directfb_event_wheel, NULL);
+ ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_GOT_FOCUS, _ecore_evas_directfb_event_got_focus, NULL);
+ ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_LOST_FOCUS, _ecore_evas_directfb_event_lost_focus, NULL);
+ ecore_evas_event_handlers[10] = NULL;
+ ecore_evas_event_handlers[11] = NULL;
+ ecore_evas_event_handlers[12] = NULL;
+
+ return _ecore_evas_init_count;
+}
+
+/* engine functions */
+/********************/
+
+static void
+_ecore_evas_directfb_free(Ecore_Evas *ee)
+{
+ eina_hash_del(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee);
+ ecore_directfb_window_free(ee->engine.directfb.window);
+ _ecore_evas_directfb_shutdown();
+ ecore_directfb_shutdown();
+}
+
+static void
+_ecore_evas_directfb_move(Ecore_Evas *ee, int x, int y)
+{
+ ecore_directfb_window_move(ee->engine.directfb.window, x, y);
+}
+
+static void
+_ecore_evas_directfb_resize(Ecore_Evas *ee, int w, int h)
+{
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ecore_directfb_window_resize(ee->engine.directfb.window, w, h);
+ ee->w = w;
+ ee->h = h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+}
+
+static void
+_ecore_evas_directfb_focus_set(Ecore_Evas *ee, int on EINA_UNUSED)
+{
+ ecore_directfb_window_focus(ee->engine.directfb.window);
+}
+
+static void
+_ecore_evas_directfb_hide(Ecore_Evas *ee)
+{
+ ecore_directfb_window_hide(ee->engine.directfb.window);
+ ee->should_be_visible = 0;
+}
+
+static void
+_ecore_evas_directfb_show(Ecore_Evas *ee)
+{
+ ecore_directfb_window_show(ee->engine.directfb.window);
+ ee->should_be_visible = 1;
+}
+
+static void
+_ecore_evas_directfb_shaped_set(Ecore_Evas *ee, int shaped)
+{
+ if (((ee->shaped) && (shaped)) || ((!ee->shaped) && (!shaped)))
+ return;
+ ee->shaped = shaped;
+ if(ee->shaped)
+ ecore_directfb_window_shaped_set(ee->engine.directfb.window, 1);
+ else
+ ecore_directfb_window_shaped_set(ee->engine.directfb.window, 0);
+
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee)
+ ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_directfb_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ ecore_directfb_window_cursor_show(ee->engine.directfb.window, 1);
+ return;
+
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+
+ ecore_directfb_window_cursor_show(ee->engine.directfb.window, 0);
+
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,x - ee->prop.cursor.hot.x,y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+static void
+_ecore_evas_directfb_fullscreen_set(Ecore_Evas *ee, int on)
+{
+ Evas_Engine_Info_DirectFB *einfo;
+ int w;
+ int h;
+ int resized = 0;
+
+ if (((ee->prop.fullscreen) && (on)) || ((!ee->prop.fullscreen) && (!on)))
+ return;
+
+ if (on)
+ ecore_directfb_window_fullscreen_set(ee->engine.directfb.window, 1);
+ else
+ ecore_directfb_window_fullscreen_set(ee->engine.directfb.window, 0);
+ /* set the new size of the evas */
+ ecore_directfb_window_size_get(ee->engine.directfb.window, &w, &h);
+ if( (ee->w != w) || (ee->h != h))
+ {
+ resized = 1;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ }
+ einfo = (Evas_Engine_Info_DirectFB *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.surface = ee->engine.directfb.window->surface;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+ ee->prop.fullscreen = on;
+ if (resized)
+ {
+ if(ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+static void *
+_ecore_evas_directfb_window_get(const Ecore_Evas *ee)
+{
+ return ee->engine.directfb.window;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+static Ecore_Evas_Engine_Func _ecore_directfb_engine_func =
+{
+ _ecore_evas_directfb_free, /* free an ecore_evas */
+ NULL, /* cb resize */
+ NULL, /* cb move */
+ NULL, /* cb show */
+ NULL, /* cb hide */
+ NULL, /* cb delete request */
+ NULL, /* cb destroy */
+ NULL, /* cb focus in */
+ NULL, /* cb focus out */
+ NULL, /* cb sticky */
+ NULL, /* cb unsticky */
+ NULL, /* cb mouse in */
+ NULL, /* cb mouse out */
+ NULL, /* cb pre render */
+ NULL, /* cb post render */
+ _ecore_evas_directfb_move, /* move */
+ NULL, /* managed move */
+ _ecore_evas_directfb_resize, /* resize */
+ NULL, /* move resize */
+ NULL,//_ecore_evas_directfb_rotation_set,/* rotation */
+ _ecore_evas_directfb_shaped_set, /* shaped */
+ _ecore_evas_directfb_show, /* show */
+ _ecore_evas_directfb_hide, /* hide */
+ NULL, /* raise */
+ NULL, /* lower */
+ NULL, /* activate */
+ NULL, /* title set */
+ NULL, /* name class set */
+ NULL, /* size min */
+ NULL, /* size max */
+ NULL, /* size base */
+ NULL, /* size step */
+ _ecore_evas_directfb_object_cursor_set, /* set cursor to an evas object */
+ NULL, /* layer set */
+ _ecore_evas_directfb_focus_set, /* focus */
+ NULL, /* iconified */
+ NULL, /* borderless */
+ NULL, /* override */
+ NULL, /* maximized */
+ _ecore_evas_directfb_fullscreen_set,/* fullscreen */
+ NULL, /* avoid damage */
+ NULL, /* withdrawn */
+ NULL, /* sticky */
+ NULL, /* ignore events */
+ NULL, /* alpha */
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+#endif
+
+/* api */
+/*******/
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+EAPI Ecore_Evas *
+ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w, int h)
+{
+ Evas_Engine_Info_DirectFB *einfo;
+ Ecore_Evas *ee;
+ Ecore_DirectFB_Window *window;
+ int rmethod;
+
+ rmethod = evas_render_method_lookup("directfb");
+ if (!rmethod) return NULL;
+ if (!ecore_directfb_init(disp_name)) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+ _ecore_evas_directfb_init();
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_directfb_engine_func;
+
+ ee->driver = "directfb";
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->rotation = 0;
+ ee->visible = 1;
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ ee->prop.layer = 1;
+ ee->prop.fullscreen = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ einfo = (Evas_Engine_Info_DirectFB *)evas_engine_info_get(ee->evas);
+
+ window = ecore_directfb_window_new(x,y,w,h);
+ ee->engine.directfb.window = window;
+ if (einfo)
+ {
+ einfo->info.dfb = ecore_directfb_interface_get();
+ einfo->info.surface = window->surface;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ ee->engine.func->fn_render = _ecore_evas_directfb_render;
+ _ecore_evas_register(ee);
+
+ if (!ecore_evases_hash)
+ ecore_evases_hash = eina_hash_string_superfast_new(NULL);
+ eina_hash_add(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee);
+
+ return ee;
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_directfb_new(const char *disp_name EINA_UNUSED, int windowed EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+EAPI Ecore_DirectFB_Window *
+ecore_evas_directfb_window_get(const Ecore_Evas *ee)
+{
+ if (!(!strcmp(ee->driver, "directfb"))) return 0;
+ return (Ecore_DirectFB_Window *) _ecore_evas_directfb_window_get(ee);
+}
+#else
+EAPI Ecore_DirectFB_Window *
+ecore_evas_directfb_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_ews.c b/src/lib/ecore_evas/ecore_evas_ews.c
new file mode 100644
index 0000000000..ceffd663e6
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_ews.c
@@ -0,0 +1,1469 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include "ecore_private.h"
+#include <Ecore_Input.h>
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+EAPI int ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_ADD = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_DEL = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_RESIZE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_MOVE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_SHOW = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_HIDE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_FOCUS = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_UNFOCUS = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_RAISE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_LOWER = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_ACTIVATE = 0;
+
+EAPI int ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_LAYER_CHANGE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE = 0;
+EAPI int ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE = 0;
+
+#ifdef BUILD_ECORE_EVAS_EWS
+static int _ecore_evas_init_count = 0;
+
+static Ecore_Evas *_ews_ee = NULL;
+static Evas_Object *_ews_bg = NULL;
+static Eina_List *_ews_children = NULL;
+static const void *_ews_manager = NULL;
+static char *_ews_engine = NULL;
+static char *_ews_options = NULL;
+static int _ews_x = 0;
+static int _ews_y = 0;
+static int _ews_w = 1024;
+static int _ews_h = 768;
+static Eina_Bool _ews_defaults_engine = EINA_TRUE;
+static Eina_Bool _ews_defaults_geo = EINA_TRUE;
+
+static const char EWS_ENGINE_NAME[] = "ews";
+
+static void
+_ecore_evas_ews_pre_free(Ecore_Evas *ee EINA_UNUSED)
+{
+ DBG("EWS backing store free'd");
+ _ews_children = eina_list_free(_ews_children);
+ _ews_ee = NULL;
+ _ews_bg = NULL;
+}
+
+static void
+_ecore_evas_ews_del_request(Ecore_Evas *ee EINA_UNUSED)
+{
+ INF("EWS backing store deletion is forbidden!");
+}
+
+static Ecore_Evas *
+_ecore_evas_ews_ee_new(void)
+{
+ Ecore_Evas *ee = ecore_evas_new(_ews_engine, _ews_x, _ews_y, _ews_w, _ews_h,
+ _ews_options);
+ if (!ee)
+ ERR("Failed: ecore_evas_new(%s, %d, %d, %d, %d, %s)",
+ _ews_engine, _ews_x, _ews_y, _ews_w, _ews_h, _ews_options);
+ else
+ {
+ ecore_evas_size_min_set(ee, _ews_w, _ews_h);
+ ecore_evas_size_max_set(ee, _ews_w, _ews_h);
+ ecore_evas_callback_pre_free_set(ee, _ecore_evas_ews_pre_free);
+ ecore_evas_callback_delete_request_set(ee, _ecore_evas_ews_del_request);
+ ecore_evas_name_class_set(ee, "ecore_evas_ews", "ews");
+ ecore_evas_title_set
+ (ee, "EWS: Ecore + Evas Single Process Windowing System");
+ ecore_evas_show(ee);
+ }
+
+ return ee;
+}
+
+static void
+_ecore_evas_ews_env_setup(void)
+{
+ const char *env = getenv("ECORE_EVAS_EWS");
+ char *p, *n, *tmp;
+
+ if (_ews_defaults_engine)
+ {
+ free(_ews_engine);
+ _ews_engine = NULL;
+ free(_ews_options);
+ _ews_options = NULL;
+ }
+ if (_ews_defaults_geo)
+ {
+ _ews_x = 0;
+ _ews_y = 0;
+ _ews_w = 1024;
+ _ews_h = 768;
+ }
+
+ if ((!env) || (!*env)) return;
+
+ p = tmp = strdup(env);
+ if (!tmp) return;
+
+ n = strchr(p, ':');
+ if (n) *n = '\0';
+ if (_ews_defaults_engine) _ews_engine = strdup(p);
+ if (!n) goto end;
+
+ p = n + 1;
+ n = strchr(p, ':');
+ if (!n) goto end;
+ *n = '\0';
+ if (_ews_defaults_geo) _ews_x = atoi(p);
+
+ p = n + 1;
+ n = strchr(p, ':');
+ if (!n) goto end;
+ *n = '\0';
+ if (_ews_defaults_geo) _ews_y = atoi(p);
+
+ p = n + 1;
+ n = strchr(p, ':');
+ if (!n) goto end;
+ *n = '\0';
+ if (_ews_defaults_geo) _ews_w = atoi(p);
+
+ p = n + 1;
+ n = strchr(p, ':');
+ if (n) *n = '\0';
+ if (_ews_defaults_geo) _ews_h = atoi(p);
+ if (!n) goto end;
+
+ p = n + 1;
+ if (_ews_defaults_engine) _ews_options = strdup(p);
+
+ end:
+ free(tmp);
+}
+
+static void
+_ecore_evas_ews_event_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Evas *ee = ev;
+ _ecore_evas_unref(ee);
+}
+
+static void
+_ecore_evas_ews_event(Ecore_Evas *ee, int event)
+{
+ _ecore_evas_ref(ee);
+ ecore_event_add(event, ee, _ecore_evas_ews_event_free, NULL);
+}
+
+static void
+_ecore_evas_ews_event_free_del(void *data EINA_UNUSED, void *ev EINA_UNUSED)
+{
+ _ecore_evas_ews_shutdown();
+}
+
+static void
+_ecore_evas_ews_free(Ecore_Evas *ee)
+{
+ evas_object_del(ee->engine.ews.image);
+ _ews_ee->sub_ecore_evas = eina_list_remove(_ews_ee->sub_ecore_evas, ee);
+
+ ecore_event_add(ECORE_EVAS_EWS_EVENT_DEL, ee, _ecore_evas_ews_event_free_del, NULL);
+}
+
+static void
+_ecore_evas_ews_move(Ecore_Evas *ee, int x, int y)
+{
+ ee->req.x = x;
+ ee->req.y = y;
+
+ if ((x == ee->x) && (y == ee->y)) return;
+ ee->x = x;
+ ee->y = y;
+ evas_object_move(ee->engine.ews.image, x, y);
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MOVE);
+}
+
+static void
+_ecore_evas_ews_managed_move(Ecore_Evas *ee, int x, int y)
+{
+ ee->req.x = x;
+ ee->req.y = y;
+
+ if ((x == ee->x) && (y == ee->y)) return;
+ ee->x = x;
+ ee->y = y;
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MOVE);
+}
+
+static void
+_ecore_evas_ews_resize_internal(Ecore_Evas *ee, int w, int h)
+{
+ Evas_Engine_Info_Buffer *einfo;
+ void *pixels;
+ int stride;
+
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, w, h);
+
+ evas_object_image_size_set(ee->engine.ews.image, w, h);
+ evas_object_image_fill_set(ee->engine.ews.image, 0, 0, w, h);
+ evas_object_resize(ee->engine.ews.image, w, h);
+
+ pixels = evas_object_image_data_get(ee->engine.ews.image, 1);
+ evas_object_image_data_set(ee->engine.ews.image, pixels); // refcount
+ stride = evas_object_image_stride_get(ee->engine.ews.image);
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ EINA_SAFETY_ON_NULL_RETURN(einfo);
+
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ einfo->info.dest_buffer = pixels;
+ einfo->info.dest_buffer_row_bytes = stride;
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ evas_object_image_data_set(ee->engine.ews.image, pixels);
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+}
+
+static void
+_ecore_evas_ews_resize(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->req.w = w;
+ ee->req.h = h;
+
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+ _ecore_evas_ews_resize_internal(ee, w, h);
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_RESIZE);
+}
+
+static void
+_ecore_evas_ews_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ _ecore_evas_ews_move(ee, x, y);
+ _ecore_evas_ews_resize(ee, w, h);
+}
+
+static void
+_ecore_evas_ews_rotation_set(Ecore_Evas *ee, int rot, int resize EINA_UNUSED)
+{
+ if (ee->rotation == rot) return;
+ ee->rotation = rot;
+
+ ERR("TODO: rot=%d, resize=%d", rot, resize);
+
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_shaped_set(Ecore_Evas *ee, int val)
+{
+ if (ee->shaped == val) return;
+ ee->shaped = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_show(Ecore_Evas *ee)
+{
+ ee->should_be_visible = EINA_TRUE;
+ evas_object_show(ee->engine.ews.image);
+ if (ee->prop.fullscreen)
+ evas_object_focus_set(ee->engine.ews.image, EINA_TRUE);
+
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_SHOW);
+}
+
+static void
+_ecore_evas_ews_hide(Ecore_Evas *ee)
+{
+ ee->should_be_visible = EINA_FALSE;
+ evas_object_hide(ee->engine.ews.image);
+
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_HIDE);
+}
+
+static void
+_ecore_evas_ews_raise(Ecore_Evas *ee)
+{
+ evas_object_raise(ee->engine.ews.image);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_RAISE);
+}
+
+static void
+_ecore_evas_ews_lower(Ecore_Evas *ee)
+{
+ evas_object_lower(ee->engine.ews.image);
+ evas_object_lower(_ews_bg);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_LOWER);
+}
+
+static void
+_ecore_evas_ews_activate(Ecore_Evas *ee)
+{
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ACTIVATE);
+}
+
+static void
+_ecore_evas_ews_title_set(Ecore_Evas *ee, const char *t)
+{
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (t) ee->prop.title = strdup(t);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
+{
+ if (ee->prop.name) free(ee->prop.name);
+ if (ee->prop.clas) free(ee->prop.clas);
+ ee->prop.name = NULL;
+ ee->prop.clas = NULL;
+ if (n) ee->prop.name = strdup(n);
+ if (c) ee->prop.clas = strdup(c);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_size_min_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return;
+ ee->prop.min.w = w;
+ ee->prop.min.h = h;
+ evas_object_size_hint_min_set(ee->engine.ews.image, w, h);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_size_max_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return;
+ ee->prop.max.w = w;
+ ee->prop.max.h = h;
+ evas_object_size_hint_max_set(ee->engine.ews.image, w, h);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_size_base_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return;
+ ee->prop.base.w = w;
+ ee->prop.base.h = h;
+ evas_object_size_hint_request_set(ee->engine.ews.image, w, h);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_size_step_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return;
+ ee->prop.step.w = w;
+ ee->prop.step.h = h;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_ews_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_DEL, _ecore_evas_ews_object_cursor_del, ee);
+
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_layer_set(Ecore_Evas *ee, int layer)
+{
+ if (layer < EVAS_LAYER_MIN + 1)
+ layer = EVAS_LAYER_MIN + 1;
+ else if (layer > EVAS_LAYER_MAX)
+ layer = EVAS_LAYER_MAX;
+
+ if (ee->prop.layer == layer) return;
+ ee->prop.layer = layer;
+ evas_object_layer_set(ee->engine.ews.image, layer);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_LAYER_CHANGE);
+}
+
+static void
+_ecore_evas_ews_focus_set(Ecore_Evas *ee, int val)
+{
+ evas_object_focus_set(ee->engine.ews.image, val);
+ ee->prop.focused = val;
+ if (val)
+ {
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_FOCUS);
+ }
+ else
+ {
+ evas_focus_out(ee->evas);
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_UNFOCUS);
+ }
+}
+
+static void
+_ecore_evas_ews_iconified_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.iconified == val) return;
+ ee->prop.iconified = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE);
+}
+
+static void
+_ecore_evas_ews_borderless_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.borderless == val) return;
+ ee->prop.borderless = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_override_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.override == val) return;
+ if (ee->visible) evas_object_show(ee->engine.ews.image);
+ if (ee->prop.focused) evas_object_focus_set(ee->engine.ews.image, EINA_TRUE);
+ ee->prop.override = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_maximized_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.maximized == val) return;
+ ee->prop.maximized = val;
+ if (val) evas_object_show(ee->engine.ews.image);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE);
+}
+
+static void
+_ecore_evas_ews_fullscreen_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.fullscreen == val) return;
+ ee->prop.fullscreen = val;
+
+ if (!val)
+ {
+ evas_object_move(ee->engine.ews.image, ee->x, ee->y);
+ evas_object_resize(ee->engine.ews.image, ee->w, ee->h);
+ }
+ else
+ {
+ Evas_Coord w, h;
+ ecore_evas_geometry_get(_ews_ee, NULL, NULL, &w, &h);
+ evas_object_move(ee->engine.ews.image, 0, 0);
+ evas_object_resize(ee->engine.ews.image, w, h);
+ evas_object_focus_set(ee->engine.ews.image, EINA_TRUE);
+ }
+
+ if (ee->should_be_visible)
+ evas_object_show(ee->engine.ews.image);
+ else
+ evas_object_hide(ee->engine.ews.image);
+
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE);
+}
+
+static void
+_ecore_evas_ews_avoid_damage_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.avoid_damage == val) return;
+ ee->prop.avoid_damage = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_withdrawn_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.withdrawn == val) return;
+ ee->prop.withdrawn = val;
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_sticky_set(Ecore_Evas *ee, int val)
+{
+ if (ee->prop.sticky == val) return;
+ ee->prop.sticky = val;
+ if ((val) && (ee->func.fn_sticky)) ee->func.fn_sticky(ee);
+ else if ((!val) && (ee->func.fn_unsticky)) ee->func.fn_unsticky(ee);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_ignore_events_set(Ecore_Evas *ee, int val)
+{
+ if (ee->ignore_events == val) return;
+ ee->ignore_events = val;
+ evas_object_pass_events_set(ee->engine.ews.image, val);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_alpha_set(Ecore_Evas *ee, int val)
+{
+ if (ee->alpha == val) return;
+ ee->alpha = val;
+ evas_object_image_alpha_set(ee->engine.ews.image, val);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static void
+_ecore_evas_ews_transparent_set(Ecore_Evas *ee, int val)
+{
+ if (ee->transparent == val) return;
+ ee->transparent = val;
+ evas_object_image_alpha_set(ee->engine.ews.image, val);
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE);
+}
+
+static int
+_ecore_evas_ews_render(Ecore_Evas *ee)
+{
+ Eina_List *updates = NULL, *l, *ll;
+ Ecore_Evas *ee2;
+ Eina_Rectangle *r;
+ int w, h, rend = 0;
+ void *pixels;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ rend |= _ecore_evas_ews_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ evas_object_image_size_get(ee->engine.ews.image, &w, &h);
+ if ((w != ee->w) || (h != ee->h))
+ ecore_evas_resize(ee, w, h);
+
+ pixels = evas_object_image_data_get(ee->engine.ews.image, 1);
+ if (pixels)
+ {
+ updates = evas_render_updates(ee->evas);
+ }
+ evas_object_image_data_set(ee->engine.ews.image, pixels);
+
+ EINA_LIST_FOREACH(updates, l, r)
+ evas_object_image_data_update_add(ee->engine.ews.image,
+ r->x, r->y, r->w, r->h);
+
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ }
+
+ return updates ? 1 : rend;
+}
+
+static void
+_ecore_evas_ews_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h)
+{
+ ecore_evas_geometry_get(_ews_ee, x, y, w, h);
+}
+
+static const Ecore_Evas_Engine_Func _ecore_ews_engine_func =
+{
+ _ecore_evas_ews_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_ews_move,
+ _ecore_evas_ews_managed_move,
+ _ecore_evas_ews_resize,
+ _ecore_evas_ews_move_resize,
+ _ecore_evas_ews_rotation_set,
+ _ecore_evas_ews_shaped_set,
+ _ecore_evas_ews_show,
+ _ecore_evas_ews_hide,
+ _ecore_evas_ews_raise,
+ _ecore_evas_ews_lower,
+ _ecore_evas_ews_activate,
+ _ecore_evas_ews_title_set,
+ _ecore_evas_ews_name_class_set,
+ _ecore_evas_ews_size_min_set,
+ _ecore_evas_ews_size_max_set,
+ _ecore_evas_ews_size_base_set,
+ _ecore_evas_ews_size_step_set,
+ _ecore_evas_ews_object_cursor_set,
+ _ecore_evas_ews_layer_set,
+ _ecore_evas_ews_focus_set,
+ _ecore_evas_ews_iconified_set,
+ _ecore_evas_ews_borderless_set,
+ _ecore_evas_ews_override_set,
+ _ecore_evas_ews_maximized_set,
+ _ecore_evas_ews_fullscreen_set,
+ _ecore_evas_ews_avoid_damage_set,
+ _ecore_evas_ews_withdrawn_set,
+ _ecore_evas_ews_sticky_set,
+ _ecore_evas_ews_ignore_events_set,
+ _ecore_evas_ews_alpha_set,
+ _ecore_evas_ews_transparent_set,
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ _ecore_evas_ews_render,
+ _ecore_evas_ews_screen_geometry_get,
+ NULL // screen_dpi_get
+};
+
+void
+_ecore_evas_ews_events_init(void)
+{
+ if (ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE != 0) return;
+ ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_ADD = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_DEL = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_RESIZE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_MOVE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_SHOW = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_HIDE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_FOCUS = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_UNFOCUS = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_RAISE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_LOWER = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_ACTIVATE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_LAYER_CHANGE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE = ecore_event_type_new();
+ ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE = ecore_event_type_new();
+}
+
+static int
+_ecore_evas_ews_init(void)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+
+ _ecore_evas_ews_env_setup();
+
+ return _ecore_evas_init_count;
+}
+
+int
+_ecore_evas_ews_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ if (_ews_ee)
+ {
+ ecore_evas_free(_ews_ee);
+ _ews_ee = NULL;
+ }
+ if (_ews_children)
+ {
+ eina_list_free(_ews_children);
+ _ews_children = NULL;
+ }
+
+ free(_ews_engine);
+ _ews_engine = NULL;
+ free(_ews_options);
+ _ews_options = NULL;
+ _ews_defaults_engine = EINA_TRUE;
+ _ews_defaults_geo = EINA_TRUE;
+
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_ews_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
+{
+ Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh;
+
+ evas_object_geometry_get(ee->engine.ews.image, &xx, &yy, &ww, &hh);
+ evas_object_image_fill_get(ee->engine.ews.image, &fx, &fy, &fw, &fh);
+
+ if (fw < 1) fw = 1;
+ if (fh < 1) fh = 1;
+
+ if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh))
+ {
+ *x = (ee->w * (*x - xx)) / fw;
+ *y = (ee->h * (*y - yy)) / fh;
+ }
+ else
+ {
+ xx = (*x - xx) - fx;
+ while (xx < 0) xx += fw;
+ while (xx > fw) xx -= fw;
+ *x = (ee->w * xx) / fw;
+
+ yy = (*y - yy) - fy;
+ while (yy < 0) yy += fh;
+ while (yy > fh) yy -= fh;
+ *y = (ee->h * yy) / fh;
+ }
+}
+
+static void
+_ecore_evas_ews_modifiers_apply(Ecore_Evas *ee, const Evas_Modifier *modifier)
+{
+ Evas *e = ee->evas;
+
+ if (evas_key_modifier_is_set(modifier, "Shift"))
+ evas_key_modifier_on(e, "Shift");
+ else evas_key_modifier_off(e, "Shift");
+
+ if (evas_key_modifier_is_set(modifier, "Control"))
+ evas_key_modifier_on(e, "Control");
+ else evas_key_modifier_off(e, "Control");
+
+ if (evas_key_modifier_is_set(modifier, "Alt"))
+ evas_key_modifier_on(e, "Alt");
+ else evas_key_modifier_off(e, "Alt");
+
+ if (evas_key_modifier_is_set(modifier, "Super"))
+ evas_key_modifier_on(e, "Super");
+ else evas_key_modifier_off(e, "Super");
+
+ if (evas_key_modifier_is_set(modifier, "Hyper"))
+ evas_key_modifier_on(e, "Hyper");
+ else evas_key_modifier_off(e, "Hyper");
+
+ if (evas_key_modifier_is_set(modifier, "Scroll_Lock"))
+ evas_key_lock_on(e, "Scroll_Lock");
+ else evas_key_lock_off(e, "Scroll_Lock");
+
+ if (evas_key_modifier_is_set(modifier, "Num_Lock"))
+ evas_key_lock_on(e, "Num_Lock");
+ else evas_key_lock_off(e, "Num_Lock");
+
+ if (evas_key_modifier_is_set(modifier, "Caps_Lock"))
+ evas_key_lock_on(e, "Caps_Lock");
+ else evas_key_lock_off(e, "Caps_Lock");
+
+ if (evas_key_modifier_is_set(modifier, "Shift_Lock"))
+ evas_key_lock_on(e, "Shift_Lock");
+ else evas_key_lock_off(e, "Shift_Lock");
+}
+
+static void
+_ecore_evas_ews_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_In *ev = event_info;
+ Evas_Coord x = ev->canvas.x;
+ Evas_Coord y = ev->canvas.y;
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee);
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL);
+ _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp);
+}
+
+static void
+_ecore_evas_ews_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Out *ev = event_info;
+ Evas_Coord x = ev->canvas.x;
+ Evas_Coord y = ev->canvas.y;
+ // TODO: consider grab mode in EWS
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+ _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp);
+}
+
+static void
+_ecore_evas_ews_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Down *ev = event_info;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_mouse_down(ee->evas, ev->button, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Up *ev = event_info;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_mouse_up(ee->evas, ev->button, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Move *ev = event_info;
+ Evas_Coord x = ev->cur.canvas.x;
+ Evas_Coord y = ev->cur.canvas.y;
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp);
+}
+
+static void
+_ecore_evas_ews_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Wheel *ev = event_info;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_mouse_wheel(ee->evas, ev->direction, ev->z, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_multi_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Down *ev = event_info;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ xf = (ev->canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_multi_down(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_multi_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Up *ev = event_info;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ xf = (ev->canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_multi_up(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_multi_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Move *ev = event_info;
+ Evas_Coord x, y, xx, yy;
+ double xf, yf;
+
+ x = ev->cur.canvas.x;
+ y = ev->cur.canvas.y;
+ xx = x;
+ yy = y;
+ _ecore_evas_ews_coord_translate(ee, &x, &y);
+ xf = (ev->cur.canvas.xsub - (double)xx) + (double)x;
+ yf = (ev->cur.canvas.ysub - (double)yy) + (double)y;
+ _ecore_evas_ews_modifiers_apply(ee, ev->modifiers);
+ evas_event_feed_multi_move(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_free(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee->driver) _ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_ews_cb_key_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Key_Down *ev = event_info;
+
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift"))
+ evas_key_modifier_on(ee->evas, "Shift");
+ else
+ evas_key_modifier_off(ee->evas, "Shift");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control"))
+ evas_key_modifier_on(ee->evas, "Control");
+ else
+ evas_key_modifier_off(ee->evas, "Control");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt"))
+ evas_key_modifier_on(ee->evas, "Alt");
+ else
+ evas_key_modifier_off(ee->evas, "Alt");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta"))
+ evas_key_modifier_on(ee->evas, "Meta");
+ else
+ evas_key_modifier_off(ee->evas, "Meta");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper"))
+ evas_key_modifier_on(ee->evas, "Hyper");
+ else
+ evas_key_modifier_off(ee->evas, "Hyper");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super"))
+ evas_key_modifier_on(ee->evas, "Super");
+ else
+ evas_key_modifier_off(ee->evas, "Super");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock"))
+ evas_key_lock_on(ee->evas, "Scroll_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Scroll_Lock");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock"))
+ evas_key_lock_on(ee->evas, "Num_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Num_Lock");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock"))
+ evas_key_lock_on(ee->evas, "Caps_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Caps_Lock");
+ evas_event_feed_key_down(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_key_up(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Key_Up *ev = event_info;
+
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift"))
+ evas_key_modifier_on(ee->evas, "Shift");
+ else
+ evas_key_modifier_off(ee->evas, "Shift");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control"))
+ evas_key_modifier_on(ee->evas, "Control");
+ else
+ evas_key_modifier_off(ee->evas, "Control");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt"))
+ evas_key_modifier_on(ee->evas, "Alt");
+ else
+ evas_key_modifier_off(ee->evas, "Alt");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta"))
+ evas_key_modifier_on(ee->evas, "Meta");
+ else
+ evas_key_modifier_off(ee->evas, "Meta");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper"))
+ evas_key_modifier_on(ee->evas, "Hyper");
+ else
+ evas_key_modifier_off(ee->evas, "Hyper");
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super"))
+ evas_key_modifier_on(ee->evas, "Super");
+ else
+ evas_key_modifier_off(ee->evas, "Super");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock"))
+ evas_key_lock_on(ee->evas, "Scroll_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Scroll_Lock");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock"))
+ evas_key_lock_on(ee->evas, "Num_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Num_Lock");
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock"))
+ evas_key_lock_on(ee->evas, "Caps_Lock");
+ else
+ evas_key_lock_off(ee->evas, "Caps_Lock");
+ evas_event_feed_key_up(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL);
+}
+
+static void
+_ecore_evas_ews_cb_focus_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_focus_set(ee, EINA_TRUE);
+}
+
+static void
+_ecore_evas_ews_cb_focus_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee->deleted) return;
+ ecore_evas_focus_set(ee, EINA_FALSE);
+}
+
+static void
+_ecore_evas_ews_cb_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_show(ee);
+}
+
+static void
+_ecore_evas_ews_cb_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee->deleted) return;
+ ecore_evas_hide(ee);
+}
+#endif
+
+EAPI Ecore_Evas *
+ecore_evas_ews_new(int x, int y, int w, int h)
+{
+// basically a copy of ecore_evas_buffer_new() keep in sync...
+#ifdef BUILD_ECORE_EVAS_EWS
+ Evas_Object *o;
+ Evas_Engine_Info_Buffer *einfo;
+ Ecore_Evas *ee;
+ int rmethod;
+
+ if (_ecore_evas_ews_init() < 1) return NULL;
+
+ if (!_ews_ee) _ews_ee = _ecore_evas_ews_ee_new();
+ if (!_ews_ee)
+ {
+ ERR("Could not create EWS backing store");
+ _ecore_evas_ews_shutdown();
+ return NULL;
+ }
+
+ rmethod = evas_render_method_lookup("buffer");
+ if (!rmethod) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ o = evas_object_image_add(_ews_ee->evas);
+ evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
+ evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_size_set(o, w, h);
+ evas_object_image_alpha_set(o, 1);
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_ews_engine_func;
+
+ ee->driver = EWS_ENGINE_NAME;
+
+ ee->x = 0;
+ ee->y = 0;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ evas_object_move(o, x, y);
+ evas_object_resize(o, w, h);
+ evas_object_image_fill_set(o, 0, 0, w, h);
+
+ ee->engine.ews.image = o;
+ evas_object_data_set(ee->engine.ews.image, "Ecore_Evas", ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_IN,
+ _ecore_evas_ews_cb_mouse_in, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_OUT,
+ _ecore_evas_ews_cb_mouse_out, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_DOWN,
+ _ecore_evas_ews_cb_mouse_down, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_UP,
+ _ecore_evas_ews_cb_mouse_up, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_MOVE,
+ _ecore_evas_ews_cb_mouse_move, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MOUSE_WHEEL,
+ _ecore_evas_ews_cb_mouse_wheel, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MULTI_DOWN,
+ _ecore_evas_ews_cb_multi_down, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MULTI_UP,
+ _ecore_evas_ews_cb_multi_up, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_MULTI_MOVE,
+ _ecore_evas_ews_cb_multi_move, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_FREE,
+ _ecore_evas_ews_cb_free, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_KEY_DOWN,
+ _ecore_evas_ews_cb_key_down, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_KEY_UP,
+ _ecore_evas_ews_cb_key_up, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_FOCUS_IN,
+ _ecore_evas_ews_cb_focus_in, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_FOCUS_OUT,
+ _ecore_evas_ews_cb_focus_out, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_SHOW,
+ _ecore_evas_ews_cb_show, ee);
+ evas_object_event_callback_add(ee->engine.ews.image,
+ EVAS_CALLBACK_HIDE,
+ _ecore_evas_ews_cb_hide, ee);
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ void *pixels = evas_object_image_data_get(o, 1);
+ evas_object_image_data_set(o, pixels); // refcount
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ einfo->info.dest_buffer = pixels;
+ einfo->info.dest_buffer_row_bytes = evas_object_image_stride_get(o);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ evas_object_image_data_set(o, pixels);
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ evas_key_modifier_add(ee->evas, "Shift");
+ evas_key_modifier_add(ee->evas, "Control");
+ evas_key_modifier_add(ee->evas, "Alt");
+ evas_key_modifier_add(ee->evas, "Meta");
+ evas_key_modifier_add(ee->evas, "Hyper");
+ evas_key_modifier_add(ee->evas, "Super");
+ evas_key_lock_add(ee->evas, "Caps_Lock");
+ evas_key_lock_add(ee->evas, "Num_Lock");
+ evas_key_lock_add(ee->evas, "Scroll_Lock");
+
+ _ews_ee->sub_ecore_evas = eina_list_append(_ews_ee->sub_ecore_evas, ee);
+ _ews_children = eina_list_append(_ews_children, ee);
+
+ _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ADD);
+
+ return ee;
+#else
+ return NULL;
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+#endif
+}
+
+EAPI Evas_Object *
+ecore_evas_ews_backing_store_get(const Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_ews_backing_store_get");
+ return NULL;
+ }
+ return ee->engine.ews.image;
+#else
+ return NULL;
+ (void)ee;
+#endif
+}
+
+EAPI void
+ecore_evas_ews_delete_request(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_ews_delete_request");
+ return;
+ }
+ if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee);
+ else ecore_evas_free(ee);
+#else
+ (void)ee;
+#endif
+}
+
+
+EAPI Eina_Bool
+ecore_evas_ews_engine_set(const char *engine, const char *options)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if (_ews_ee) return EINA_FALSE;
+
+ free(_ews_engine);
+ free(_ews_options);
+
+ _ews_engine = engine ? strdup(engine) : NULL;
+ _ews_options = options ? strdup(options) : NULL;
+
+ if ((engine) && (!_ews_engine)) return EINA_FALSE;
+ if ((options) && (!_ews_options)) return EINA_FALSE;
+
+ _ews_defaults_engine = EINA_FALSE;
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)engine;
+ (void)options;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_evas_ews_setup(int x, int y, int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ Eina_Bool ret = EINA_TRUE;
+
+ _ews_defaults_geo = EINA_FALSE;
+ _ews_x = x;
+ _ews_y = y;
+ _ews_w = w;
+ _ews_h = h;
+
+ if (!_ews_ee) return EINA_TRUE;
+
+ /* move-resize is not as implemented as move + resize */
+ ecore_evas_move(_ews_ee, x, y);
+ ecore_evas_size_min_set(_ews_ee, w, h);
+ ecore_evas_size_max_set(_ews_ee, w, h);
+ ecore_evas_resize(_ews_ee, w, h);
+
+ ecore_evas_geometry_get(_ews_ee, &x, &y, &w, &h);
+
+#define TST(n) if ((n != _ews_##n)) \
+ { \
+ WRN("Asked %d, got %d for "#n, _ews_##n, n); \
+ ret = EINA_FALSE; \
+ }
+ TST(x);
+ TST(y);
+ TST(w);
+ TST(h);
+#undef TST
+ return ret;
+#else
+ return EINA_FALSE;
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+#endif
+}
+
+EAPI Ecore_Evas *
+ecore_evas_ews_ecore_evas_get(void)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if (!_ews_ee) _ews_ee = _ecore_evas_ews_ee_new();
+ return _ews_ee;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Evas *
+ecore_evas_ews_evas_get(void)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ return ecore_evas_get(ecore_evas_ews_ecore_evas_get());
+#else
+ return NULL;
+#endif
+}
+
+EAPI Evas_Object *
+ecore_evas_ews_background_get(void)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ return _ews_bg;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef BUILD_ECORE_EVAS_EWS
+static void
+_ecore_evas_ews_background_free(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ _ews_bg = NULL;
+ ecore_evas_ews_background_set(NULL);
+}
+#endif
+
+EAPI void
+ecore_evas_ews_background_set(Evas_Object *o)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if ((o) && (o == _ews_bg)) return;
+
+ if (_ews_bg)
+ {
+ evas_object_del(_ews_bg);
+ _ews_bg = NULL;
+ }
+
+ if ((!o) && (_ews_ee))
+ {
+ o = evas_object_rectangle_add(ecore_evas_get(_ews_ee));
+ evas_object_color_set(o, 0, 0, 0, 255);
+ }
+
+ if (_ews_ee)
+ {
+ Evas_Coord w, h;
+ Evas *e = ecore_evas_get(_ews_ee);
+
+ if (e != evas_object_evas_get(o))
+ {
+ ERR("background not in ecore_evas_ews_evas_get() canvas!");
+ return;
+ }
+
+ evas_output_viewport_get(e, NULL, NULL, &w, &h);
+ evas_object_move(o, 0, 0);
+ evas_object_resize(o, w, h);
+ evas_object_layer_set(o, EVAS_LAYER_MIN);
+ evas_object_lower(o);
+ evas_object_show(o);
+
+ evas_object_event_callback_add
+ (o, EVAS_CALLBACK_FREE, _ecore_evas_ews_background_free, NULL);
+ }
+
+ _ews_bg = o;
+#else
+ return;
+ (void)o;
+#endif
+}
+
+
+EAPI const Eina_List *
+ecore_evas_ews_children_get(void)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ return _ews_children;
+#else
+ return NULL;
+#endif
+}
+
+EAPI void
+ecore_evas_ews_manager_set(const void *manager)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ if (_ews_manager == manager) return;
+ _ews_manager = manager;
+ ecore_event_add(ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE, NULL, NULL, NULL);
+#else
+ (void)manager;
+#endif
+}
+
+EAPI const void *
+ecore_evas_ews_manager_get(void)
+{
+#ifdef BUILD_ECORE_EVAS_EWS
+ return _ews_manager;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/lib/ecore_evas/ecore_evas_extn.c b/src/lib/ecore_evas/ecore_evas_extn.c
new file mode 100644
index 0000000000..2e1dac5cf8
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_extn.c
@@ -0,0 +1,2266 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/file.h>
+#include <unistd.h>
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#include <Ecore_Input.h>
+
+#ifdef BUILD_ECORE_EVAS_EXTN
+
+#include <Ecore_Ipc.h>
+
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+
+#ifdef BUILD_ECORE_EVAS_EXTN
+
+
+typedef struct _Shmfile Shmfile;
+
+struct _Shmfile
+{
+ int fd;
+ int size;
+ void *addr;
+ const char *file;
+};
+
+static int blank = 0x00000000;
+
+static Shmfile *
+shmfile_new(const char *base, int id, int size, Eina_Bool sys)
+{
+ Shmfile *sf;
+ char file[PATH_MAX];
+
+ sf = calloc(1, sizeof(Shmfile));
+ do
+ {
+ mode_t mode;
+
+ snprintf(file, sizeof(file), "/%s-%i-%i.%i.%i",
+ base, id, (int)time(NULL), (int)getpid(), (int)rand());
+ mode = S_IRUSR | S_IWUSR;
+ if (sys) mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ sf->fd = shm_open(file, O_RDWR | O_CREAT | O_EXCL, mode);
+ }
+ while (sf->fd < 0);
+
+ sf->file = eina_stringshare_add(file);
+ if (!sf->file)
+ {
+ close(sf->fd);
+ shm_unlink(sf->file);
+ eina_stringshare_del(sf->file);
+ free(sf);
+ return NULL;
+ }
+ sf->size = size;
+ if (ftruncate(sf->fd, size) < 0)
+ {
+ close(sf->fd);
+ shm_unlink(sf->file);
+ eina_stringshare_del(sf->file);
+ free(sf);
+ return NULL;
+ }
+ sf->addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, sf->fd, 0);
+ if (sf->addr == MAP_FAILED)
+ {
+ close(sf->fd);
+ shm_unlink(sf->file);
+ eina_stringshare_del(sf->file);
+ free(sf);
+ return NULL;
+ }
+ return sf;
+}
+
+void
+shmfile_free(Shmfile *sf)
+{
+ munmap(sf->addr, sf->size);
+ close(sf->fd);
+ shm_unlink(sf->file);
+ eina_stringshare_del(sf->file);
+ free(sf);
+}
+
+static Shmfile *
+shmfile_open(const char *ref, int size, Eina_Bool sys)
+{
+ Shmfile *sf;
+ mode_t mode;
+
+ sf = calloc(1, sizeof(Shmfile));
+ mode = S_IRUSR | S_IWUSR;
+ if (sys) mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ sf->fd = shm_open(ref, O_RDWR, mode);
+ if (sf->fd < 0)
+ {
+ free(sf);
+ return NULL;
+ }
+ sf->file = eina_stringshare_add(ref);
+ if (!sf->file)
+ {
+ close(sf->fd);
+ eina_stringshare_del(sf->file);
+ free(sf);
+ return NULL;
+ }
+ sf->size = size;
+ sf->addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, sf->fd, 0);
+ if (sf->addr == MAP_FAILED)
+ {
+ close(sf->fd);
+ eina_stringshare_del(sf->file);
+ free(sf);
+ return NULL;
+ }
+ return sf;
+}
+
+void
+shmfile_close(Shmfile *sf)
+{
+ munmap(sf->addr, sf->size);
+ close(sf->fd);
+ eina_stringshare_del(sf->file);
+ free(sf);
+}
+
+// procotol version - change this as needed
+#define MAJOR 0x1011
+
+enum // opcodes
+{
+ OP_RESIZE,
+ OP_SHOW,
+ OP_HIDE,
+ OP_FOCUS,
+ OP_UNFOCUS,
+ OP_UPDATE,
+ OP_UPDATE_DONE,
+ OP_LOCK_FILE,
+ OP_SHM_REF,
+ OP_EV_MOUSE_IN,
+ OP_EV_MOUSE_OUT,
+ OP_EV_MOUSE_UP,
+ OP_EV_MOUSE_DOWN,
+ OP_EV_MOUSE_MOVE,
+ OP_EV_MOUSE_WHEEL,
+ OP_EV_MULTI_UP,
+ OP_EV_MULTI_DOWN,
+ OP_EV_MULTI_MOVE,
+ OP_EV_KEY_UP,
+ OP_EV_KEY_DOWN,
+ OP_EV_HOLD
+};
+
+enum
+{
+ MOD_SHIFT = (1 << 0),
+ MOD_CTRL = (1 << 1),
+ MOD_ALT = (1 << 2),
+ MOD_META = (1 << 3),
+ MOD_HYPER = (1 << 4),
+ MOD_SUPER = (1 << 5),
+ MOD_CAPS = (1 << 6),
+ MOD_NUM = (1 << 7),
+ MOD_SCROLL = (1 << 8),
+};
+
+typedef struct _Ipc_Data_Resize Ipc_Data_Resize;
+typedef struct _Ipc_Data_Update Ipc_Data_Update;
+typedef struct _Ipc_Data_Ev_Mouse_In Ipc_Data_Ev_Mouse_In;
+typedef struct _Ipc_Data_Ev_Mouse_Out Ipc_Data_Ev_Mouse_Out;
+typedef struct _Ipc_Data_Ev_Mouse_Up Ipc_Data_Ev_Mouse_Up;
+typedef struct _Ipc_Data_Ev_Mouse_Down Ipc_Data_Ev_Mouse_Down;
+typedef struct _Ipc_Data_Ev_Mouse_Move Ipc_Data_Ev_Mouse_Move;
+typedef struct _Ipc_Data_Ev_Mouse_Wheel Ipc_Data_Ev_Mouse_Wheel;
+typedef struct _Ipc_Data_Ev_Hold Ipc_Data_Ev_Hold;
+typedef struct _Ipc_Data_Ev_Multi_Up Ipc_Data_Ev_Multi_Up;
+typedef struct _Ipc_Data_Ev_Multi_Down Ipc_Data_Ev_Multi_Down;
+typedef struct _Ipc_Data_Ev_Multi_Move Ipc_Data_Ev_Multi_Move;
+typedef struct _Ipc_Data_Ev_Key_Up Ipc_Data_Ev_Key_Up;
+typedef struct _Ipc_Data_Ev_Key_Down Ipc_Data_Ev_Key_Down;
+
+struct _Ipc_Data_Resize
+{
+ int w, h;
+};
+
+struct _Ipc_Data_Update
+{
+ int x, w, y, h;
+};
+
+struct _Ipc_Data_Ev_Mouse_In
+{
+ unsigned int timestamp;
+ int mask;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Mouse_Out
+{
+ unsigned int timestamp;
+ int mask;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Mouse_Up
+{
+ int b;
+ Evas_Button_Flags flags;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Mouse_Down
+{
+ int b;
+ Evas_Button_Flags flags;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Mouse_Move
+{
+ int x, y;
+ Evas_Button_Flags flags;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Mouse_Wheel
+{
+ int direction, z;
+ Evas_Button_Flags flags;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Hold
+{
+ int hold;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Multi_Up
+{
+ Evas_Button_Flags flags;
+ int d, x, y;
+ double rad, radx, rady, pres, ang, fx, fy;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Multi_Down
+{
+ Evas_Button_Flags flags;
+ int d, x, y;
+ double rad, radx, rady, pres, ang, fx, fy;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Multi_Move
+{
+ int d, x, y;
+ double rad, radx, rady, pres, ang, fx, fy;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Key_Up
+{
+ const char *keyname, *key, *string, *compose;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+struct _Ipc_Data_Ev_Key_Down
+{
+ const char *keyname, *key, *string, *compose;
+ int mask;
+ unsigned int timestamp;
+ Evas_Event_Flags event_flags;
+};
+
+typedef struct _Extn Extn;
+
+struct _Extn
+{
+ struct {
+ Ecore_Ipc_Server *server;
+ Eina_List *clients;
+ Eina_List *handlers;
+ Eina_Bool am_server : 1;
+ } ipc;
+ struct {
+ const char *name;
+ int num;
+ Eina_Bool sys : 1;
+ } svc;
+ struct {
+ const char *lock;
+ int lockfd;
+ const char *shm;
+ int w, h;
+ Shmfile *shmfile;
+ Eina_List *updates;
+ Eina_Bool have_lock : 1;
+ Eina_Bool have_real_lock : 1;
+ } file;
+};
+
+static Eina_List *extn_ee_list = NULL;
+
+EAPI int ECORE_EVAS_EXTN_CLIENT_ADD = 0;
+EAPI int ECORE_EVAS_EXTN_CLIENT_DEL = 0;
+
+void
+_ecore_evas_extn_init(void)
+{
+ if (ECORE_EVAS_EXTN_CLIENT_ADD) return;
+ ECORE_EVAS_EXTN_CLIENT_ADD = ecore_event_type_new();
+ ECORE_EVAS_EXTN_CLIENT_DEL = ecore_event_type_new();
+}
+
+void
+_ecore_evas_extn_shutdown(void)
+{
+}
+
+static void
+_ecore_evas_extn_event_free(void *data, void *ev EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee->engine.buffer.image)
+ evas_object_unref(ee->engine.buffer.image);
+ _ecore_evas_unref(ee);
+}
+
+static void
+_ecore_evas_extn_event(Ecore_Evas *ee, int event)
+{
+ _ecore_evas_ref(ee);
+ if (ee->engine.buffer.image)
+ evas_object_ref(ee->engine.buffer.image);
+ ecore_event_add(event, ee->engine.buffer.image,
+ _ecore_evas_extn_event_free, ee);
+}
+
+static Eina_Bool
+_ecore_evas_lock_other_have(Ecore_Evas *ee)
+{
+ Eina_List *l;
+ Ecore_Evas *ee2;
+ Extn *extn, *extn2;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return EINA_FALSE;
+ // brute force - i know. i expect extn_ee_list to be fairly short. could
+ // be improved with a hash of lockfiles
+ EINA_LIST_FOREACH(extn_ee_list, l, ee2)
+ {
+ if (ee == ee2) continue;
+ extn2 = ee2->engine.buffer.data;
+ if (!extn2) continue;
+ if ((extn->file.lock) && (extn2->file.lock) &&
+ (!strcmp(extn->file.lock, extn2->file.lock)) &&
+ (extn2->file.have_real_lock))
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_ecore_evas_socket_lock(Ecore_Evas *ee)
+{
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->file.lockfd < 0) return;
+ if (extn->file.have_lock) return;
+ extn->file.have_lock = EINA_TRUE;
+ if (_ecore_evas_lock_other_have(ee)) return;
+ flock(extn->file.lockfd, LOCK_EX);
+ extn->file.have_real_lock = EINA_TRUE;
+}
+
+static void
+_ecore_evas_socket_unlock(Ecore_Evas *ee)
+{
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->file.lockfd < 0) return;
+ if (!extn->file.have_lock) return;
+ extn->file.have_lock = EINA_FALSE;
+ if (!extn->file.have_real_lock) return;
+ flock(extn->file.lockfd, LOCK_UN);
+}
+
+static void
+_ecore_evas_extn_plug_targer_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee) _ecore_evas_socket_lock(ee);
+}
+
+static void
+_ecore_evas_extn_plug_targer_render_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee) _ecore_evas_socket_unlock(ee);
+}
+
+static void
+_ecore_evas_extn_plug_image_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ if (ee) ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_extn_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
+{
+ Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh;
+
+ evas_object_geometry_get(ee->engine.buffer.image, &xx, &yy, &ww, &hh);
+ evas_object_image_fill_get(ee->engine.buffer.image, &fx, &fy, &fw, &fh);
+
+ if (fw < 1) fw = 1;
+ if (fh < 1) fh = 1;
+
+ if (evas_object_map_get(ee->engine.buffer.image) &&
+ evas_object_map_enable_get(ee->engine.buffer.image))
+ {
+ fx = 0; fy = 0;
+ fw = ee->w; fh = ee->h;
+ ww = ee->w; hh = ee->h;
+ }
+
+ if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh))
+ {
+ *x = (ee->w * (*x - xx)) / fw;
+ *y = (ee->h * (*y - yy)) / fh;
+ }
+ else
+ {
+ xx = (*x - xx) - fx;
+ while (xx < 0) xx += fw;
+ while (xx > fw) xx -= fw;
+ *x = (ee->w * xx) / fw;
+
+ yy = (*y - yy) - fy;
+ while (yy < 0) yy += fh;
+ while (yy > fh) yy -= fh;
+ *y = (ee->h * yy) / fh;
+ }
+}
+
+static void
+_ecore_evas_extn_free(Ecore_Evas *ee)
+{
+ Extn *extn;
+ Ecore_Ipc_Client *client;
+
+ extn = ee->engine.buffer.data;
+ if (extn)
+ {
+ Ecore_Event_Handler *hdl;
+
+ if (extn->file.have_lock)
+ _ecore_evas_socket_unlock(ee);
+ if (extn->file.lockfd)
+ {
+ close(extn->file.lockfd);
+ if (extn->ipc.am_server)
+ {
+ if (extn->file.lock) unlink(extn->file.lock);
+ }
+ }
+ if (extn->svc.name) eina_stringshare_del(extn->svc.name);
+ if (extn->ipc.clients)
+ {
+ EINA_LIST_FREE(extn->ipc.clients, client)
+ ecore_ipc_client_del(client);
+ }
+ if (extn->ipc.server) ecore_ipc_server_del(extn->ipc.server);
+ if (extn->file.lock) eina_stringshare_del(extn->file.lock);
+ if (extn->file.shm) eina_stringshare_del(extn->file.shm);
+ if (extn->file.shmfile)
+ {
+ if (extn->ipc.am_server)
+ shmfile_free(extn->file.shmfile);
+ else
+ shmfile_close(extn->file.shmfile);
+ }
+
+ EINA_LIST_FREE(extn->ipc.handlers, hdl)
+ ecore_event_handler_del(hdl);
+ free(extn);
+ ecore_ipc_shutdown();
+ ee->engine.buffer.data = NULL;
+ }
+ if (ee->engine.buffer.image)
+ {
+ Ecore_Evas *ee2;
+
+ evas_object_event_callback_del_full(ee->engine.buffer.image,
+ EVAS_CALLBACK_DEL,
+ _ecore_evas_extn_plug_image_obj_del,
+ ee);
+ evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image),
+ EVAS_CALLBACK_RENDER_PRE,
+ _ecore_evas_extn_plug_targer_render_pre,
+ ee);
+ evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image),
+ EVAS_CALLBACK_RENDER_POST,
+ _ecore_evas_extn_plug_targer_render_post,
+ ee);
+ evas_object_del(ee->engine.buffer.image);
+ ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent");
+ if (ee2)
+ {
+ ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee);
+ }
+ }
+ extn_ee_list = eina_list_remove(extn_ee_list, ee);
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+
+ /*
+ * No need for it if not used later.
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ */
+ if (ee->engine.buffer.image)
+ evas_object_image_size_set(ee->engine.buffer.image, ee->w, ee->h);
+ /* Server can have many plugs, so I block resize comand from client to server *
+ if ((extn) && (extn->ipc.server))
+ {
+ Ipc_Data_Resize ipc;
+
+ ipc.w = ee->w;
+ ipc.h = ee->h;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_RESIZE, 0, 0, 0, &ipc, sizeof(ipc));
+ }*/
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ _ecore_evas_resize(ee, w, h);
+}
+
+static int
+_ecore_evas_modifiers_locks_mask_get(Evas *e)
+{
+ int mask = 0;
+
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift"))
+ mask |= MOD_SHIFT;
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control"))
+ mask |= MOD_CTRL;
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt"))
+ mask |= MOD_ALT;
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta"))
+ mask |= MOD_META;
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper"))
+ mask |= MOD_HYPER;
+ if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super"))
+ mask |= MOD_SUPER;
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock"))
+ mask |= MOD_SCROLL;
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock"))
+ mask |= MOD_NUM;
+ if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock"))
+ mask |= MOD_CAPS;
+ return mask;
+}
+
+static void
+_ecore_evas_modifiers_locks_mask_set(Evas *e, int mask)
+{
+ if (mask & MOD_SHIFT) evas_key_modifier_on (e, "Shift");
+ else evas_key_modifier_off(e, "Shift");
+ if (mask & MOD_CTRL) evas_key_modifier_on (e, "Control");
+ else evas_key_modifier_off(e, "Control");
+ if (mask & MOD_ALT) evas_key_modifier_on (e, "Alt");
+ else evas_key_modifier_off(e, "Alt");
+ if (mask & MOD_META) evas_key_modifier_on (e, "Meta");
+ else evas_key_modifier_off(e, "Meta");
+ if (mask & MOD_HYPER) evas_key_modifier_on (e, "Hyper");
+ else evas_key_modifier_off(e, "Hyper");
+ if (mask & MOD_SUPER) evas_key_modifier_on (e, "Super");
+ else evas_key_modifier_off(e, "Super");
+ if (mask & MOD_SCROLL) evas_key_lock_on (e, "Scroll_Lock");
+ else evas_key_lock_off(e, "Scroll_Lock");
+ if (mask & MOD_NUM) evas_key_lock_on (e, "Num_Lock");
+ else evas_key_lock_off(e, "Num_Lock");
+ if (mask & MOD_CAPS) evas_key_lock_on (e, "Caps_Lock");
+ else evas_key_lock_off(e, "Caps_Lock");
+}
+
+static void
+_ecore_evas_extn_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_In *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Mouse_In ipc;
+ memset(&ipc, 0, sizeof(ipc));
+
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_IN, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Out *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Mouse_Out ipc;
+ memset(&ipc, 0, sizeof(ipc));
+
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_OUT, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Down *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ /* We have send mouse move event before mouse down event */
+ {
+ Ipc_Data_Ev_Mouse_Move ipc_move;
+ memset(&ipc_move, 0, sizeof(ipc_move));
+ Evas_Coord x, y;
+
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ _ecore_evas_extn_coord_translate(ee, &x, &y);
+ ipc_move.x = x;
+ ipc_move.y = y;
+ ipc_move.timestamp = ev->timestamp;
+ ipc_move.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc_move.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_MOVE, 0, 0, 0, &ipc_move, sizeof(ipc_move));
+ }
+ {
+ Ipc_Data_Ev_Mouse_Down ipc;
+ memset(&ipc, 0, sizeof(ipc));
+ ipc.b = ev->button;
+ ipc.flags = ev->flags;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_DOWN, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+ }
+}
+
+static void
+_ecore_evas_extn_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Up *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Mouse_Up ipc;
+ memset(&ipc, 0, sizeof(ipc));
+
+ ipc.b = ev->button;
+ ipc.flags = ev->flags;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_UP, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Move *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Mouse_Move ipc;
+ memset(&ipc, 0, sizeof(ipc));
+ Evas_Coord x, y;
+
+ x = ev->cur.canvas.x;
+ y = ev->cur.canvas.y;
+ _ecore_evas_extn_coord_translate(ee, &x, &y);
+ ipc.x = x;
+ ipc.y = y;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_MOVE, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Mouse_Wheel *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Mouse_Wheel ipc;
+ memset(&ipc, 0, sizeof(ipc));
+
+ ipc.direction = ev->direction;
+ ipc.z = ev->z;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_WHEEL, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_multi_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Down *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Multi_Down ipc;
+ memset(&ipc, 0, sizeof(ipc));
+ Evas_Coord x, y;
+
+ ipc.d = ev->device;
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ _ecore_evas_extn_coord_translate(ee, &x, &y);
+ ipc.x = x;
+ ipc.y = y;
+ ipc.rad = ev->radius;
+ ipc.radx = ev->radius_x;
+ ipc.rady = ev->radius_y;
+ ipc.pres = ev->pressure;
+ ipc.ang = ev->angle;
+ ipc.fx = ev->canvas.xsub;
+ ipc.fy = ev->canvas.ysub;
+ ipc.flags = ev->flags;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_DOWN, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+
+static void
+_ecore_evas_extn_cb_multi_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Up *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Multi_Up ipc;
+ memset(&ipc, 0, sizeof(ipc));
+ Evas_Coord x, y;
+
+ ipc.d = ev->device;
+ x = ev->canvas.x;
+ y = ev->canvas.y;
+ _ecore_evas_extn_coord_translate(ee, &x, &y);
+ ipc.x = x;
+ ipc.y = y;
+ ipc.rad = ev->radius;
+ ipc.radx = ev->radius_x;
+ ipc.rady = ev->radius_y;
+ ipc.pres = ev->pressure;
+ ipc.ang = ev->angle;
+ ipc.fx = ev->canvas.xsub;
+ ipc.fy = ev->canvas.ysub;
+ ipc.flags = ev->flags;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_UP, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_multi_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Multi_Move *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Multi_Move ipc;
+ memset(&ipc, 0, sizeof(ipc));
+ Evas_Coord x, y;
+
+ ipc.d = ev->device;
+ x = ev->cur.canvas.x;
+ y = ev->cur.canvas.y;
+ _ecore_evas_extn_coord_translate(ee, &x, &y);
+ ipc.x = x;
+ ipc.y = y;
+ ipc.rad = ev->radius;
+ ipc.radx = ev->radius_x;
+ ipc.rady = ev->radius_y;
+ ipc.pres = ev->pressure;
+ ipc.ang = ev->angle;
+ ipc.fx = ev->cur.canvas.xsub;
+ ipc.fy = ev->cur.canvas.ysub;
+ ipc.timestamp = ev->timestamp;
+ ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_MOVE, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_free(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee->driver) _ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_extn_cb_key_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Key_Down *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Key_Down *ipc;
+ char *st, *p;
+ int len = 0;
+
+ len = sizeof(Ipc_Data_Ev_Key_Down);
+ if (ev->key) len += strlen(ev->key) + 1;
+ if (ev->keyname) len += strlen(ev->keyname) + 1;
+ if (ev->string) len += strlen(ev->string) + 1;
+ if (ev->compose) len += strlen(ev->compose) + 1;
+ len += 1;
+ st = alloca(len);
+ ipc = (Ipc_Data_Ev_Key_Down *)st;
+ memset(st, 0, len);
+ p = st + sizeof(Ipc_Data_Ev_Key_Down);
+ if (ev->key)
+ {
+ strcpy(p, ev->key);
+ ipc->key = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->keyname)
+ {
+ strcpy(p, ev->keyname);
+ ipc->keyname = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->string)
+ {
+ strcpy(p, ev->string);
+ ipc->string = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->compose)
+ {
+ strcpy(p, ev->compose);
+ ipc->compose = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ ipc->timestamp = ev->timestamp;
+ ipc->mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc->event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_KEY_DOWN, 0, 0, 0, ipc, len);
+ }
+}
+
+static void
+_ecore_evas_extn_cb_key_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Key_Up *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Key_Up *ipc;
+ char *st, *p;
+ int len = 0;
+
+ len = sizeof(Ipc_Data_Ev_Key_Up);
+ if (ev->key) len += strlen(ev->key) + 1;
+ if (ev->keyname) len += strlen(ev->keyname) + 1;
+ if (ev->string) len += strlen(ev->string) + 1;
+ if (ev->compose) len += strlen(ev->compose) + 1;
+ len += 1;
+ st = alloca(len);
+ ipc = (Ipc_Data_Ev_Key_Up *)st;
+ memset(st, 0, len);
+ p = st + sizeof(Ipc_Data_Ev_Key_Down);
+ if (ev->key)
+ {
+ strcpy(p, ev->key);
+ ipc->key = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->keyname)
+ {
+ strcpy(p, ev->keyname);
+ ipc->keyname = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->string)
+ {
+ strcpy(p, ev->string);
+ ipc->string = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ if (ev->compose)
+ {
+ strcpy(p, ev->compose);
+ ipc->compose = p - (long)st;
+ p += strlen(p) + 1;
+ }
+ ipc->timestamp = ev->timestamp;
+ ipc->mask = _ecore_evas_modifiers_locks_mask_get(ee->evas);
+ ipc->event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_KEY_UP, 0, 0, 0, ipc, len);
+ }
+}
+
+static void
+_ecore_evas_extn_cb_hold(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
+{
+ Ecore_Evas *ee = data;
+ Evas_Event_Hold *ev = event_info;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (extn->ipc.server)
+ {
+ Ipc_Data_Ev_Hold ipc;
+ memset(&ipc, 0, sizeof(ipc));
+
+ ipc.hold = ev->hold;
+ ipc.timestamp = ev->timestamp;
+ ipc.event_flags = ev->event_flags;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_HOLD, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+}
+
+static void
+_ecore_evas_extn_cb_focus_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Extn *extn;
+
+ ee = data;
+ ee->prop.focused = 1;
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (!extn->ipc.server) return;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_FOCUS, 0, 0, 0, NULL, 0);
+}
+
+static void
+_ecore_evas_extn_cb_focus_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Extn *extn;
+
+ ee = data;
+ ee->prop.focused = 0;
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (!extn->ipc.server) return;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_UNFOCUS, 0, 0, 0, NULL, 0);
+}
+
+static void
+_ecore_evas_extn_cb_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Extn *extn;
+
+ ee = data;
+ ee->visible = 1;
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (!extn->ipc.server) return;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_SHOW, 0, 0, 0, NULL, 0);
+}
+
+static void
+_ecore_evas_extn_cb_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Extn *extn;
+
+ ee = data;
+ ee->visible = 0;
+ extn = ee->engine.buffer.data;
+ if (!extn) return;
+ if (!extn->ipc.server) return;
+ ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_HIDE, 0, 0, 0, NULL, 0);
+}
+
+static const Ecore_Evas_Engine_Func _ecore_extn_plug_engine_func =
+{
+ _ecore_evas_extn_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //transparent
+ NULL, // profiles_set
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+
+static Eina_Bool
+_ipc_server_add(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Server_Add *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+
+ if (ee != ecore_ipc_server_data_get(e->server))
+ return ECORE_CALLBACK_PASS_ON;
+ if (!eina_list_data_find(extn_ee_list, ee))
+ return ECORE_CALLBACK_PASS_ON;
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+ //FIXME: find a way to let app know server there
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ipc_server_del(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Server_Del *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+ if (extn->ipc.server != e->server) return ECORE_CALLBACK_PASS_ON;
+ evas_object_image_data_set(ee->engine.buffer.image, NULL);
+ ee->engine.buffer.pixels = NULL;
+ if (extn->file.shmfile)
+ {
+ shmfile_close(extn->file.shmfile);
+ extn->file.shmfile = NULL;
+ }
+ if (extn->file.shm)
+ {
+ eina_stringshare_del(extn->file.shm);
+ extn->file.shm = NULL;
+ }
+ extn->ipc.server = NULL;
+ if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ipc_server_data(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Server_Data *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+
+ if (ee != ecore_ipc_server_data_get(e->server))
+ return ECORE_CALLBACK_PASS_ON;
+ if (!eina_list_data_find(extn_ee_list, ee))
+ return ECORE_CALLBACK_PASS_ON;
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+ if (e->major != MAJOR)
+ return ECORE_CALLBACK_PASS_ON;
+ switch (e->minor)
+ {
+ case OP_UPDATE:
+ // add rect to update list
+ if (e->size >= (int)sizeof(Ipc_Data_Update))
+ {
+ Ipc_Data_Update *ipc = malloc(sizeof(Ipc_Data_Update));
+ if (ipc)
+ {
+ memcpy(ipc, e->data, sizeof(Ipc_Data_Update));
+ extn->file.updates = eina_list_append(extn->file.updates, ipc);
+ }
+ }
+ break;
+ case OP_UPDATE_DONE:
+ // updates finished being sent - done now. frame ready
+ {
+ Ipc_Data_Update *ipc;
+
+ EINA_LIST_FREE(extn->file.updates, ipc)
+ {
+ if (ee->engine.buffer.image)
+ evas_object_image_data_update_add(ee->engine.buffer.image,
+ ipc->x, ipc->y,
+ ipc->w, ipc->h);
+ }
+ }
+ break;
+ case OP_LOCK_FILE:
+ if ((e->data) && (e->size > 0) &&
+ (((unsigned char *)e->data)[e->size - 1] == 0))
+ {
+ if (extn->file.have_lock) _ecore_evas_socket_unlock(ee);
+ if (extn->file.lockfd) close(extn->file.lockfd);
+ if (extn->file.lock) eina_stringshare_del(extn->file.lock);
+ extn->file.lock = eina_stringshare_add(e->data);
+ extn->file.lockfd = open(extn->file.lock, O_RDONLY);
+ }
+ break;
+ case OP_SHM_REF:
+ // e->ref == w
+ // e->ref_to == h
+ // e->response == alpha
+ // e->data = shm ref string + nul byte
+ if ((e->data) && ((unsigned char *)e->data)[e->size - 1] == 0)
+ {
+ ee->engine.buffer.pixels = NULL;
+ if (extn->file.shmfile)
+ {
+ shmfile_close(extn->file.shmfile);
+ extn->file.shmfile = NULL;
+ }
+ if (extn->file.shm)
+ {
+ eina_stringshare_del(extn->file.shm);
+ extn->file.shm = NULL;
+ }
+ if ((e->ref > 0) && (e->ref_to > 0))
+ {
+ extn->file.w = e->ref;
+ extn->file.h = e->ref_to;
+ extn->file.shm = eina_stringshare_add(e->data);
+ extn->file.shmfile = shmfile_open(extn->file.shm,
+ extn->file.w *
+ extn->file.h * 4,
+ EINA_TRUE);
+ if (extn->file.shmfile)
+ {
+ ee->engine.buffer.pixels = extn->file.shmfile->addr;
+ if (ee->engine.buffer.image)
+ {
+ if (e->response)
+ evas_object_image_alpha_set(ee->engine.buffer.image,
+ EINA_TRUE);
+ else
+ evas_object_image_alpha_set(ee->engine.buffer.image,
+ EINA_FALSE);
+ evas_object_image_size_set(ee->engine.buffer.image,
+ extn->file.w,
+ extn->file.h);
+ evas_object_image_data_set(ee->engine.buffer.image,
+ ee->engine.buffer.pixels);
+ evas_object_image_data_update_add(ee->engine.buffer.image,
+ 0, 0,
+ extn->file.w,
+ extn->file.h);
+ _ecore_evas_resize(ee,
+ extn->file.w,
+ extn->file.h);
+ }
+ else
+ evas_object_image_data_set(ee->engine.buffer.image, NULL);
+ }
+ else
+ evas_object_image_data_set(ee->engine.buffer.image, NULL);
+ }
+ else
+ evas_object_image_data_set(ee->engine.buffer.image, NULL);
+ }
+ break;
+ case OP_RESIZE:
+ if ((e->data) && (e->size >= (int)sizeof(Ipc_Data_Resize)))
+ {
+ Ipc_Data_Resize *ipc = e->data;
+ _ecore_evas_resize(ee, ipc->w, ipc->h);
+ }
+ break;
+ default:
+ break;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+#else
+void
+_ecore_evas_extn_init(void)
+{
+}
+
+void
+_ecore_evas_extn_shutdown(void)
+{
+}
+
+#endif /* BUILD_ECORE_EVAS_EXTN */
+
+EAPI Evas_Object *
+ecore_evas_extn_plug_new(Ecore_Evas *ee_target)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Evas_Object *o;
+ Ecore_Evas *ee;
+ int w = 1, h = 1;
+
+ if (!ee_target) return NULL;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ o = evas_object_image_filled_add(ee_target->evas);
+ /* this make problem in gl engine, so I'll block this until solve problem
+ evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);*/
+ evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888);
+ evas_object_image_alpha_set(o, 1);
+ evas_object_image_size_set(o, 1, 1);
+ evas_object_image_data_set(o, &blank);
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_extn_plug_engine_func;
+
+ ee->driver = "extn_plug";
+
+ ee->rotation = 0;
+ ee->visible = 0;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 0;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 0;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+
+ ee->engine.buffer.image = o;
+ evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas", ee);
+ evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas_Parent", ee_target);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_IN,
+ _ecore_evas_extn_cb_mouse_in, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_OUT,
+ _ecore_evas_extn_cb_mouse_out, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_DOWN,
+ _ecore_evas_extn_cb_mouse_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_UP,
+ _ecore_evas_extn_cb_mouse_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_MOVE,
+ _ecore_evas_extn_cb_mouse_move, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MOUSE_WHEEL,
+ _ecore_evas_extn_cb_mouse_wheel, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_DOWN,
+ _ecore_evas_extn_cb_multi_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_UP,
+ _ecore_evas_extn_cb_multi_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_MULTI_MOVE,
+ _ecore_evas_extn_cb_multi_move, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FREE,
+ _ecore_evas_extn_cb_free, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_KEY_DOWN,
+ _ecore_evas_extn_cb_key_down, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_KEY_UP,
+ _ecore_evas_extn_cb_key_up, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_HOLD,
+ _ecore_evas_extn_cb_hold, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FOCUS_IN,
+ _ecore_evas_extn_cb_focus_in, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_FOCUS_OUT,
+ _ecore_evas_extn_cb_focus_out, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_SHOW,
+ _ecore_evas_extn_cb_show, ee);
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_HIDE,
+ _ecore_evas_extn_cb_hide, ee);
+
+ evas_object_event_callback_add(ee->engine.buffer.image,
+ EVAS_CALLBACK_DEL,
+ _ecore_evas_extn_plug_image_obj_del, ee);
+
+
+ extn_ee_list = eina_list_append(extn_ee_list, ee);
+ ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee);
+
+ evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_PRE,
+ _ecore_evas_extn_plug_targer_render_pre, ee);
+ evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_POST,
+ _ecore_evas_extn_plug_targer_render_post, ee);
+ return o;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_evas_extn_plug_connect(Evas_Object *obj, const char *svcname, int svcnum, Eina_Bool svcsys)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Extn *extn;
+ Ecore_Evas *ee = NULL;
+
+ if (!obj) return EINA_FALSE;
+
+ ee = evas_object_data_get(obj, "Ecore_Evas");
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) return EINA_FALSE;
+
+ if (!svcname)
+ {
+ ee->engine.buffer.data = NULL;
+ return EINA_FALSE;
+ }
+
+ extn = calloc(1, sizeof(Extn));
+ if (!extn) return EINA_FALSE;
+
+ Ecore_Ipc_Type ipctype = ECORE_IPC_LOCAL_USER;
+
+ ecore_ipc_init();
+ extn->svc.name = eina_stringshare_add(svcname);
+ extn->svc.num = svcnum;
+ extn->svc.sys = svcsys;
+
+ if (extn->svc.sys) ipctype = ECORE_IPC_LOCAL_SYSTEM;
+ extn->ipc.server = ecore_ipc_server_connect(ipctype, (char *)extn->svc.name,
+ extn->svc.num, ee);
+ if (!extn->ipc.server)
+ {
+ ee->engine.buffer.data = NULL;
+ eina_stringshare_del(extn->svc.name);
+ free(extn);
+ ecore_ipc_shutdown();
+ return EINA_FALSE;
+ }
+ ee->engine.buffer.data = extn;
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD,
+ _ipc_server_add, ee));
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL,
+ _ipc_server_del, ee));
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA,
+ _ipc_server_data, ee));
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+EAPI void
+ecore_evas_extn_plug_object_data_lock(Evas_Object *obj)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Ecore_Evas *ee;
+
+ ee = ecore_evas_object_ecore_evas_get(obj);
+ if (!ee) return;
+ _ecore_evas_socket_lock(ee);
+#endif
+}
+
+EAPI void
+ecore_evas_extn_plug_object_data_unlock(Evas_Object *obj)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Ecore_Evas *ee;
+
+ ee = ecore_evas_object_ecore_evas_get(obj);
+ if (!ee) return;
+ _ecore_evas_socket_unlock(ee);
+#endif
+}
+
+#ifdef BUILD_ECORE_EVAS_EXTN
+static void
+_ecore_evas_socket_resize(Ecore_Evas *ee, int w, int h)
+{
+ Extn *extn;
+ Evas_Engine_Info_Buffer *einfo;
+ int stride = 0;
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ extn = ee->engine.buffer.data;
+ if (extn)
+ {
+ if (extn->file.shmfile)
+ shmfile_free(extn->file.shmfile);
+ ee->engine.buffer.pixels = NULL;
+ extn->file.shmfile = shmfile_new(extn->svc.name, extn->svc.num,
+ ee->w * ee->h * 4, extn->svc.sys);
+ if (extn->file.shmfile)
+ ee->engine.buffer.pixels = extn->file.shmfile->addr;
+
+ stride = ee->w * 4;
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->alpha)
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ else
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.dest_buffer = ee->engine.buffer.pixels;
+ einfo->info.dest_buffer_row_bytes = stride;
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+
+ if (extn->ipc.clients && extn->file.shmfile)
+ {
+ Ipc_Data_Resize ipc;
+ Eina_List *l;
+ Ecore_Ipc_Client *client;
+
+ EINA_LIST_FOREACH(extn->ipc.clients, l, client)
+ ecore_ipc_client_send(client, MAJOR, OP_SHM_REF,
+ ee->w, ee->h, ee->alpha,
+ extn->file.shmfile->file,
+ strlen(extn->file.shmfile->file) + 1);
+ ipc.w = ee->w;
+ ipc.h = ee->h;
+ EINA_LIST_FOREACH(extn->ipc.clients, l, client)
+ ecore_ipc_client_send(client, MAJOR, OP_RESIZE,
+ 0, 0, 0, &ipc, sizeof(ipc));
+ }
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_socket_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ _ecore_evas_socket_resize(ee, w, h);
+}
+
+int
+_ecore_evas_extn_socket_render(Ecore_Evas *ee)
+{
+ Eina_List *updates = NULL, *l, *ll;
+ Ecore_Evas *ee2;
+ int rend = 0;
+ Eina_Rectangle *r;
+ Extn *extn;
+ Ecore_Ipc_Client *client;
+
+ extn = ee->engine.buffer.data;
+ if (!extn) return rend;
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+ if (ee->engine.buffer.pixels)
+ {
+ _ecore_evas_socket_lock(ee);
+ updates = evas_render_updates(ee->evas);
+ _ecore_evas_socket_unlock(ee);
+ }
+ EINA_LIST_FOREACH(updates, l, r)
+ {
+ Ipc_Data_Update ipc;
+
+
+ ipc.x = r->x;
+ ipc.y = r->y;
+ ipc.w = r->w;
+ ipc.h = r->h;
+ EINA_LIST_FOREACH(extn->ipc.clients, ll, client)
+ ecore_ipc_client_send(client, MAJOR, OP_UPDATE, 0, 0, 0, &ipc, sizeof(ipc));
+ }
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ EINA_LIST_FOREACH(extn->ipc.clients, ll, client)
+ ecore_ipc_client_send(client, MAJOR, OP_UPDATE_DONE, 0, 0, 0, NULL, 0);
+ }
+
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ return updates ? 1 : rend;
+}
+
+static Eina_Bool
+_ipc_client_add(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Client_Add *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+
+ if (ee != ecore_ipc_server_data_get(ecore_ipc_client_server_get(e->client)))
+ return ECORE_CALLBACK_PASS_ON;
+ if (!eina_list_data_find(extn_ee_list, ee))
+ return ECORE_CALLBACK_PASS_ON;
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+
+ extn->ipc.clients = eina_list_append(extn->ipc.clients, e->client);
+ ecore_ipc_client_send(e->client, MAJOR, OP_LOCK_FILE, 0, 0, 0, extn->file.lock, strlen(extn->file.lock) + 1);
+
+ if (extn->file.shmfile)
+ {
+ Ipc_Data_Resize ipc;
+
+ ecore_ipc_client_send(e->client, MAJOR, OP_SHM_REF,
+ ee->w, ee->h, ee->alpha,
+ extn->file.shmfile->file,
+ strlen(extn->file.shmfile->file) + 1);
+ ipc.w = ee->w;
+ ipc.h = ee->h;
+
+ ecore_ipc_client_send(e->client, MAJOR, OP_RESIZE,
+ 0, 0, 0, &ipc, sizeof(ipc));
+ }
+ _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_ADD);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ipc_client_del(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Client_Del *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+ if (!eina_list_data_find(extn->ipc.clients, e->client)) return ECORE_CALLBACK_PASS_ON;
+
+ extn->ipc.clients = eina_list_remove(extn->ipc.clients, e->client);
+
+ _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_DEL);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ipc_client_data(void *data, int type EINA_UNUSED, void *event)
+{
+ Ecore_Ipc_Event_Client_Data *e = event;
+ Ecore_Evas *ee = data;
+ Extn *extn;
+
+ if (ee != ecore_ipc_server_data_get(ecore_ipc_client_server_get(e->client)))
+ return ECORE_CALLBACK_PASS_ON;
+ if (!eina_list_data_find(extn_ee_list, ee))
+ return ECORE_CALLBACK_PASS_ON;
+ extn = ee->engine.buffer.data;
+ if (!extn) return ECORE_CALLBACK_PASS_ON;
+ if (e->major != MAJOR)
+ return ECORE_CALLBACK_PASS_ON;
+ switch (e->minor)
+ {
+ case OP_RESIZE:
+ if ((e->data) && (e->size >= (int)sizeof(Ipc_Data_Resize)))
+ {
+
+ Ipc_Data_Resize *ipc = e->data;
+ /* create callbacke data size changed */
+ _ecore_evas_socket_resize(ee, ipc->w, ipc->h);
+ }
+ break;
+ case OP_SHOW:
+ if (!ee->visible)
+ {
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+ }
+ break;
+ case OP_HIDE:
+ if (ee->visible)
+ {
+ ee->visible = 0;
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+ }
+ break;
+ case OP_FOCUS:
+ if (!ee->prop.focused)
+ {
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ }
+ break;
+ case OP_UNFOCUS:
+ if (ee->prop.focused)
+ {
+ ee->prop.focused = 0;
+ evas_focus_out(ee->evas);
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ }
+ break;
+ case OP_EV_MOUSE_IN:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_In))
+ {
+ Ipc_Data_Ev_Mouse_In *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_in(ee->evas, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MOUSE_OUT:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Out))
+ {
+ Ipc_Data_Ev_Mouse_Out *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_out(ee->evas, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MOUSE_UP:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Up))
+ {
+ Ipc_Data_Ev_Mouse_Up *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_up(ee->evas, ipc->b, ipc->flags, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MOUSE_DOWN:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Down))
+ {
+ Ipc_Data_Ev_Mouse_Up *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_down(ee->evas, ipc->b, ipc->flags, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MOUSE_MOVE:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Move))
+ {
+ Ipc_Data_Ev_Mouse_Move *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_move(ee->evas, ipc->x, ipc->y, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MOUSE_WHEEL:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Wheel))
+ {
+ Ipc_Data_Ev_Mouse_Wheel *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_mouse_wheel(ee->evas, ipc->direction, ipc->z, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MULTI_UP:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Up))
+ {
+ Ipc_Data_Ev_Multi_Up *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_multi_up(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->flags, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MULTI_DOWN:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Down))
+ {
+ Ipc_Data_Ev_Multi_Down *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_multi_down(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->flags, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ case OP_EV_MULTI_MOVE:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Move))
+ {
+ Ipc_Data_Ev_Multi_Move *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_multi_move(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+
+#define STRGET(val) \
+ do { \
+ if ((ipc->val) && (ipc->val < (char *)(long)(e->size - 1))) \
+ ipc->val = ((char *)ipc) + (long)ipc->val; \
+ else \
+ ipc->val = NULL; \
+ } while (0)
+
+ case OP_EV_KEY_UP:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Key_Up))
+ {
+ if ((e->data) && (e->size > 0) &&
+ (((unsigned char *)e->data)[e->size - 1] == 0))
+ {
+ Ipc_Data_Ev_Key_Up *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ STRGET(keyname);
+ STRGET(key);
+ STRGET(string);
+ STRGET(compose);
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_key_up(ee->evas, ipc->keyname, ipc->key, ipc->string, ipc->compose, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ }
+ break;
+ case OP_EV_KEY_DOWN:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Key_Down))
+ {
+ if ((e->data) && (e->size > 0) &&
+ (((unsigned char *)e->data)[e->size - 1] == 0))
+ {
+ Ipc_Data_Ev_Key_Down *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ STRGET(keyname);
+ STRGET(key);
+ STRGET(string);
+ STRGET(compose);
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask);
+ evas_event_feed_key_down(ee->evas, ipc->keyname, ipc->key, ipc->string, ipc->compose, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ }
+ break;
+ case OP_EV_HOLD:
+ if (e->size >= (int)sizeof(Ipc_Data_Ev_Hold))
+ {
+ Ipc_Data_Ev_Hold *ipc = e->data;
+ Evas_Event_Flags flags;
+
+ flags = evas_event_default_flags_get(ee->evas);
+ evas_event_default_flags_set(ee->evas, ipc->event_flags);
+ evas_event_feed_hold(ee->evas, ipc->hold, ipc->timestamp, NULL);
+ evas_event_default_flags_set(ee->evas, flags);
+ }
+ break;
+ default:
+ break;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_ecore_evas_extn_socket_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ Extn *extn;
+ Eina_List *l;
+ Ecore_Ipc_Client *client;
+
+ if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha))) return;
+ ee->alpha = alpha;
+
+ extn = ee->engine.buffer.data;
+ if (extn)
+ {
+ Evas_Engine_Info_Buffer *einfo;
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->alpha)
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ else
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ EINA_LIST_FOREACH(extn->ipc.clients, l, client)
+ ecore_ipc_client_send(client, MAJOR, OP_SHM_REF,
+ ee->w, ee->h, ee->alpha,
+ extn->file.shmfile->file,
+ strlen(extn->file.shmfile->file) + 1);
+ }
+}
+
+static const Ecore_Evas_Engine_Func _ecore_extn_socket_engine_func =
+{
+ _ecore_evas_extn_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_socket_resize,
+ _ecore_evas_socket_move_resize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_extn_socket_alpha_set,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ _ecore_evas_extn_socket_render, // render
+ NULL, // screen_geometry_get
+ NULL, // screen_dpi_get
+};
+
+#endif
+
+EAPI Ecore_Evas *
+ecore_evas_extn_socket_new(int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Evas_Engine_Info_Buffer *einfo;
+ Ecore_Evas *ee;
+ int rmethod;
+
+ rmethod = evas_render_method_lookup("buffer");
+ if (!rmethod) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_extn_socket_engine_func;
+
+ ee->driver = "extn_socket";
+
+ ee->rotation = 0;
+ ee->visible = 0;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 0;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 0;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->alpha)
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
+ else
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.dest_buffer = NULL;
+ einfo->info.dest_buffer_row_bytes = 0;
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ evas_key_modifier_add(ee->evas, "Shift");
+ evas_key_modifier_add(ee->evas, "Control");
+ evas_key_modifier_add(ee->evas, "Alt");
+ evas_key_modifier_add(ee->evas, "Meta");
+ evas_key_modifier_add(ee->evas, "Hyper");
+ evas_key_modifier_add(ee->evas, "Super");
+ evas_key_lock_add(ee->evas, "Caps_Lock");
+ evas_key_lock_add(ee->evas, "Num_Lock");
+ evas_key_lock_add(ee->evas, "Scroll_Lock");
+
+ extn_ee_list = eina_list_append(extn_ee_list, ee);
+
+ _ecore_evas_register(ee);
+
+ return ee;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_evas_extn_socket_listen(Ecore_Evas *ee, const char *svcname, int svcnum, Eina_Bool svcsys)
+{
+#ifdef BUILD_ECORE_EVAS_EXTN
+ Extn *extn;
+
+ extn = calloc(1, sizeof(Extn));
+ if (!extn)
+ {
+ return EINA_FALSE;
+ }
+ else
+ {
+ Ecore_Ipc_Type ipctype = ECORE_IPC_LOCAL_USER;
+ char buf[PATH_MAX];
+
+ ecore_ipc_init();
+ extn->svc.name = eina_stringshare_add(svcname);
+ extn->svc.num = svcnum;
+ extn->svc.sys = svcsys;
+
+ snprintf(buf, sizeof(buf), "/tmp/ee-lock-XXXXXX");
+ extn->file.lockfd = mkstemp(buf);
+ if (extn->file.lockfd >= 0)
+ extn->file.lock = eina_stringshare_add(buf);
+ if ((extn->file.lockfd < 0) || (!extn->file.lock))
+ {
+ if (extn->file.lockfd)
+ {
+ close(extn->file.lockfd);
+ unlink(buf);
+ }
+ eina_stringshare_del(extn->svc.name);
+ if (extn->file.lock) eina_stringshare_del(extn->file.lock);
+ free(extn);
+ ecore_ipc_shutdown();
+ return EINA_FALSE;
+ }
+
+ if (extn->svc.sys) ipctype = ECORE_IPC_LOCAL_SYSTEM;
+ extn->ipc.am_server = EINA_TRUE;
+ extn->ipc.server = ecore_ipc_server_add(ipctype,
+ (char *)extn->svc.name,
+ extn->svc.num, ee);
+ if (!extn->ipc.server)
+ {
+ if (extn->file.lockfd)
+ {
+ close(extn->file.lockfd);
+ if (extn->file.lock) unlink(extn->file.lock);
+ }
+ eina_stringshare_del(extn->svc.name);
+ eina_stringshare_del(extn->file.lock);
+ free(extn);
+ ecore_ipc_shutdown();
+ return EINA_FALSE;
+ }
+ ee->engine.buffer.data = extn;
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_ADD,
+ _ipc_client_add, ee));
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL,
+ _ipc_client_del, ee));
+ extn->ipc.handlers = eina_list_append
+ (extn->ipc.handlers,
+ ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA,
+ _ipc_client_data, ee));
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
diff --git a/src/lib/ecore_evas/ecore_evas_fb.c b/src/lib/ecore_evas/ecore_evas_fb.c
new file mode 100644
index 0000000000..0f98e62d06
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_fb.c
@@ -0,0 +1,678 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#ifdef BUILD_ECORE_EVAS_FB
+#include <Ecore_Fb.h>
+#include <ecore_fb_private.h>
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_FB
+static int _ecore_evas_init_count = 0;
+
+static char *ecore_evas_default_display = "0";
+static Eina_List *ecore_evas_input_devices = NULL;
+static Ecore_Event_Handler *ecore_evas_event_handlers[4] = {NULL, NULL, NULL, NULL};
+
+static void
+_ecore_evas_mouse_move_process_fb(Ecore_Evas *ee, int x, int y)
+{
+ int fbw, fbh;
+
+ ee->mouse.x = x;
+ ee->mouse.y = y;
+ ecore_fb_size_get(&fbw, &fbh);
+ if (ee->prop.cursor.object)
+ {
+ evas_object_show(ee->prop.cursor.object);
+ if (ee->rotation == 0)
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 90)
+ evas_object_move(ee->prop.cursor.object,
+ (fbh - ee->h) + ee->h - y - 1 - ee->prop.cursor.hot.x,
+ x - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 180)
+ evas_object_move(ee->prop.cursor.object,
+ (fbw - ee->w) + ee->w - x - 1 - ee->prop.cursor.hot.x,
+ (fbh - ee->h) + ee->h - y - 1 - ee->prop.cursor.hot.y);
+ else if (ee->rotation == 270)
+ evas_object_move(ee->prop.cursor.object,
+ y - ee->prop.cursor.hot.x,
+ (fbw - ee->w) + ee->w - x - 1 - ee->prop.cursor.hot.y);
+ }
+}
+
+static Ecore_Evas *fb_ee = NULL;
+
+static Ecore_Evas *
+_ecore_evas_fb_match(void)
+{
+ return fb_ee;
+}
+
+static void
+_ecore_evas_fb_lose(void *data EINA_UNUSED)
+{
+ Eina_List *ll;
+ Ecore_Fb_Input_Device *dev;
+
+ if (fb_ee) fb_ee->visible = 0;
+
+ EINA_LIST_FOREACH(ecore_evas_input_devices, ll, dev)
+ ecore_fb_input_device_listen(dev, 0);
+}
+
+static void
+_ecore_evas_fb_gain(void *data EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ Eina_List *ll;
+ Ecore_Fb_Input_Device *dev;
+
+ if (fb_ee)
+ {
+ ee = fb_ee;
+
+ ee->visible = 1;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+
+ EINA_LIST_FOREACH(ecore_evas_input_devices, ll, dev)
+ ecore_fb_input_device_listen(dev, 1);
+}
+
+static Eina_Bool
+_ecore_evas_event_mouse_button_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Event_Mouse_Button *e;
+
+ e = event;
+ ee = _ecore_evas_fb_match();
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ _ecore_evas_mouse_move_process_fb(ee, e->x, e->y);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_event_mouse_button_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Event_Mouse_Button *e;
+
+ e = event;
+ ee = _ecore_evas_fb_match();
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ _ecore_evas_mouse_move_process_fb(ee, e->x, e->y);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_event_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Event_Mouse_Move *e;
+
+ e = event;
+ ee = _ecore_evas_fb_match();
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ _ecore_evas_mouse_move_process_fb(ee, e->x, e->y);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_event_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Event_Mouse_Wheel *e;
+
+ e = event;
+ ee = _ecore_evas_fb_match();
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ _ecore_evas_mouse_move_process_fb(ee, e->x, e->y);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_fb_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+
+ if (ee->visible)
+ {
+ Eina_List *updates;
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ updates = evas_render_updates(ee->evas);
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ rend = 1;
+ }
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ }
+ else
+ evas_norender(ee->evas);
+ return rend;
+}
+
+static int
+_ecore_evas_fb_init(Ecore_Evas *ee, int w, int h)
+{
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *ls;
+ Ecore_Fb_Input_Device *device;
+ Ecore_Fb_Input_Device_Cap caps;
+ int mouse_handled = 0;
+
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+
+ ecore_event_evas_init();
+
+ /* register all input devices */
+ ls = eina_file_direct_ls("/dev/input/");
+
+ EINA_ITERATOR_FOREACH(ls, info)
+ {
+ if (strncmp(info->path + info->name_start, "event", 5) != 0)
+ continue;
+
+ if (!(device = ecore_fb_input_device_open(info->path)))
+ continue;
+ ecore_fb_input_device_window_set(device, ee);
+
+ caps = ecore_fb_input_device_cap_get(device);
+
+ /* Mouse */
+#ifdef HAVE_TSLIB
+ if (caps & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE)
+#else
+ if ((caps & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE) || (caps & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE))
+#endif
+ {
+ ecore_fb_input_device_axis_size_set(device, w, h);
+ ecore_fb_input_device_listen(device,1);
+ ecore_evas_input_devices = eina_list_append(ecore_evas_input_devices, device);
+ if (!mouse_handled)
+ {
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL);
+ ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, _ecore_evas_event_mouse_wheel, NULL);
+ mouse_handled = 1;
+ }
+ }
+ /* Keyboard */
+ else if ((caps & ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS) && !(caps & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE))
+ {
+ ecore_fb_input_device_listen(device,1);
+ ecore_evas_input_devices = eina_list_append(ecore_evas_input_devices, device);
+ }
+ }
+ eina_iterator_free(ls);
+
+ if (!mouse_handled)
+ {
+ if (ecore_fb_ts_init())
+ {
+ ecore_fb_ts_event_window_set(ee);
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL);
+ mouse_handled = 1;
+ }
+ }
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_fb_free(Ecore_Evas *ee)
+{
+ ecore_evas_input_event_unregister(ee);
+ if (fb_ee == ee) fb_ee = NULL;
+ _ecore_evas_fb_shutdown();
+ ecore_fb_shutdown();
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ ee->req.w = w;
+ ee->req.h = h;
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSED)
+{
+ Evas_Engine_Info_FB *einfo;
+ int rot_dif;
+
+ if (ee->rotation == rotation) return;
+ einfo = (Evas_Engine_Info_FB *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+ rot_dif = ee->rotation - rotation;
+ if (rot_dif < 0) rot_dif = -rot_dif;
+ if (rot_dif != 180)
+ {
+
+ einfo->info.rotation = rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ if (!ee->prop.fullscreen)
+ {
+ int tmp;
+
+ tmp = ee->w;
+ ee->w = ee->h;
+ ee->h = tmp;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ }
+ else
+ {
+ if ((rotation == 0) || (rotation == 180))
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ }
+ ee->rotation = rotation;
+ }
+ else
+ {
+ einfo->info.rotation = rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ ee->rotation = rotation;
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ _ecore_evas_mouse_move_process_fb(ee, ee->mouse.x, ee->mouse.y);
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_show(Ecore_Evas *ee)
+{
+ if (ee->prop.focused) return;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+}
+
+static void
+_ecore_evas_hide(Ecore_Evas *ee)
+{
+ if (ee->prop.focused)
+ {
+ ee->prop.focused = 0;
+ evas_focus_out(ee->evas);
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ }
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee)
+ ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+static void
+_ecore_evas_fullscreen_set(Ecore_Evas *ee, int on)
+{
+ Eina_List *l;
+ Ecore_Fb_Input_Device *dev;
+ int resized = 0;
+
+ if (((ee->prop.fullscreen) && (on)) ||
+ ((!ee->prop.fullscreen) && (!on))) return;
+ if (on)
+ {
+ int w, h;
+
+ ee->engine.fb.real_w = ee->w;
+ ee->engine.fb.real_h = ee->h;
+ w = ee->w;
+ h = ee->h;
+ ecore_fb_size_get(&w, &h);
+ if ((w == 0) && (h == 0))
+ {
+ w = ee->w;
+ h = ee->h;
+ }
+ if ((w != ee->w) || (h != ee->h)) resized = 1;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ else
+ {
+ if ((ee->engine.fb.real_w != ee->w) || (ee->engine.fb.real_h != ee->h)) resized = 1;
+ ee->w = ee->engine.fb.real_w;
+ ee->h = ee->engine.fb.real_h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ ee->prop.fullscreen = on;
+ EINA_LIST_FOREACH(ecore_evas_input_devices, l, dev)
+ ecore_fb_input_device_axis_size_set(dev, ee->w, ee->h);
+ /* rescale the input device area */
+ if (resized)
+ {
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+int
+_ecore_evas_fb_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (ecore_evas_event_handlers[i])
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ }
+ ecore_fb_ts_shutdown();
+ ecore_event_evas_shutdown();
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static Ecore_Evas_Engine_Func _ecore_fb_engine_func =
+{
+ _ecore_evas_fb_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ _ecore_evas_rotation_set,
+ NULL,
+ _ecore_evas_show,
+ _ecore_evas_hide,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_object_cursor_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_fullscreen_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+#endif
+
+/**
+ * @brief Create Ecore_Evas using fb backend.
+ * @param disp_name The name of the display to be used.
+ * @param rotation The rotation to be used.
+ * @param w The width of the Ecore_Evas to be created.
+ * @param h The height of the Ecore_Evas to be created.
+ * @return The new Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_FB
+EAPI Ecore_Evas *
+ecore_evas_fb_new(const char *disp_name, int rotation, int w, int h)
+{
+ Evas_Engine_Info_FB *einfo;
+ Ecore_Evas *ee;
+
+ int rmethod;
+
+ if (!disp_name)
+ disp_name = ecore_evas_default_display;
+
+ rmethod = evas_render_method_lookup("fb");
+ if (!rmethod) return NULL;
+
+ if (!ecore_fb_init(disp_name)) return NULL;
+ ecore_fb_callback_gain_set(_ecore_evas_fb_gain, NULL);
+ ecore_fb_callback_lose_set(_ecore_evas_fb_lose, NULL);
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_fb_init(ee, w, h);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_fb_engine_func;
+
+ ee->driver = "fb";
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->rotation = rotation;
+ ee->visible = 1;
+ ee->w = w;
+ ee->h = h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 0;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 1;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+
+ if ((rotation == 90) || (rotation == 270))
+ {
+ evas_output_size_set(ee->evas, h, w);
+ evas_output_viewport_set(ee->evas, 0, 0, h, w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ }
+
+ einfo = (Evas_Engine_Info_FB *)evas_engine_info_get(ee->evas);
+ if (einfo && disp_name)
+ {
+ einfo->info.virtual_terminal = 0;
+ einfo->info.device_number = strtol(disp_name, NULL, 10);
+ einfo->info.refresh = 0;
+ einfo->info.rotation = ee->rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ ecore_evas_input_event_register(ee);
+
+ ee->engine.func->fn_render = _ecore_evas_fb_render;
+ _ecore_evas_register(ee);
+ fb_ee = ee;
+ evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
+ return ee;
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_fb_new(const char *disp_name EINA_UNUSED, int rotation EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h
new file mode 100644
index 0000000000..0c7b03043d
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_private.h
@@ -0,0 +1,490 @@
+#ifndef _ECORE_EVAS_PRIVATE_H
+#define _ECORE_EVAS_PRIVATE_H
+
+#include <Evas.h>
+#include <Ecore.h>
+#include <ecore_private.h>
+#include <Ecore_Input.h>
+#include <Ecore_Input_Evas.h>
+
+#define ECORE_MAGIC_EVAS 0x76543211
+
+#ifdef BUILD_ECORE_EVAS_X11
+# include <Ecore_X.h>
+# include <Ecore_X_Atoms.h>
+# ifdef HAVE_ECORE_X_XCB
+# include <xcb/xcb.h>
+# endif
+# ifdef HAVE_ECORE_X_XLIB
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# endif
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+# include <Evas_Engine_Software_X11.h>
+#endif
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+# include <Evas_Engine_GL_X11.h>
+#endif
+
+#ifdef BUILD_ECORE_EVAS_FB
+# include <Evas_Engine_FB.h>
+#endif
+
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+# include <Evas_Engine_DirectFB.h>
+# include "Ecore_DirectFB.h"
+#endif
+
+#if defined(BUILD_ECORE_EVAS_SOFTWARE_BUFFER) || defined(BUILD_ECORE_EVAS_EWS)
+# include <Evas_Engine_Buffer.h>
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WIN32
+# include "Ecore_Win32.h"
+# ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+# include <Evas_Engine_Software_Gdi.h>
+# endif
+# ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+# include <Evas_Engine_Software_DDraw.h>
+# endif
+# ifdef BUILD_ECORE_EVAS_DIRECT3D
+# include <Evas_Engine_Direct3D.h>
+# endif
+# ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+# include <Evas_Engine_GL_Glew.h>
+# endif
+#endif
+
+#ifdef BUILD_ECORE_EVAS_GL_COCOA
+# include "Ecore_Cocoa.h"
+# include <Evas_Engine_Gl_Cocoa.h>
+#endif
+
+#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL)
+# include "Ecore_Wayland.h"
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+# include <Evas_Engine_Wayland_Shm.h>
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+# include <Evas_Engine_Wayland_Egl.h>
+#endif
+
+/** Log domain macros and variables **/
+
+extern int _ecore_evas_log_dom;
+
+#ifdef ECORE_EVAS_DEFAULT_LOG_COLOR
+# undef ECORE_EVAS_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_EVAS_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_evas_log_dom, __VA_ARGS__)
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_evas_log_dom, __VA_ARGS__)
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_evas_log_dom, __VA_ARGS__)
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_evas_log_dom, __VA_ARGS__)
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_evas_log_dom, __VA_ARGS__)
+
+
+#define IDLE_FLUSH_TIME 0.5
+#ifndef _ECORE_EVAS_H
+typedef struct _Ecore_Evas Ecore_Evas;
+typedef void (*Ecore_Evas_Event_Cb) (Ecore_Evas *ee);
+#endif
+
+typedef struct _Ecore_Evas_Engine Ecore_Evas_Engine;
+typedef struct _Ecore_Evas_Engine_Func Ecore_Evas_Engine_Func;
+
+struct _Ecore_Evas_Engine_Func
+{
+ void (*fn_free) (Ecore_Evas *ee);
+ void (*fn_callback_resize_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_move_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_show_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_hide_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_delete_request_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_destroy_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_focus_in_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_focus_out_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_mouse_in_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_mouse_out_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_sticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_unsticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_pre_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_callback_post_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ void (*fn_move) (Ecore_Evas *ee, int x, int y);
+ void (*fn_managed_move) (Ecore_Evas *ee, int x, int y);
+ void (*fn_resize) (Ecore_Evas *ee, int w, int h);
+ void (*fn_move_resize) (Ecore_Evas *ee, int x, int y, int w, int h);
+ void (*fn_rotation_set) (Ecore_Evas *ee, int rot, int resize);
+ void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
+ void (*fn_show) (Ecore_Evas *ee);
+ void (*fn_hide) (Ecore_Evas *ee);
+ void (*fn_raise) (Ecore_Evas *ee);
+ void (*fn_lower) (Ecore_Evas *ee);
+ void (*fn_activate) (Ecore_Evas *ee);
+ void (*fn_title_set) (Ecore_Evas *ee, const char *t);
+ void (*fn_name_class_set) (Ecore_Evas *ee, const char *n, const char *c);
+ void (*fn_size_min_set) (Ecore_Evas *ee, int w, int h);
+ void (*fn_size_max_set) (Ecore_Evas *ee, int w, int h);
+ void (*fn_size_base_set) (Ecore_Evas *ee, int w, int h);
+ void (*fn_size_step_set) (Ecore_Evas *ee, int w, int h);
+ void (*fn_object_cursor_set) (Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y);
+ void (*fn_layer_set) (Ecore_Evas *ee, int layer);
+ void (*fn_focus_set) (Ecore_Evas *ee, int on);
+ void (*fn_iconified_set) (Ecore_Evas *ee, int on);
+ void (*fn_borderless_set) (Ecore_Evas *ee, int on);
+ void (*fn_override_set) (Ecore_Evas *ee, int on);
+ void (*fn_maximized_set) (Ecore_Evas *ee, int on);
+ void (*fn_fullscreen_set) (Ecore_Evas *ee, int on);
+ void (*fn_avoid_damage_set) (Ecore_Evas *ee, int on);
+ void (*fn_withdrawn_set) (Ecore_Evas *ee, int withdrawn);
+ void (*fn_sticky_set) (Ecore_Evas *ee, int sticky);
+ void (*fn_ignore_events_set) (Ecore_Evas *ee, int ignore);
+ void (*fn_alpha_set) (Ecore_Evas *ee, int alpha);
+ void (*fn_transparent_set) (Ecore_Evas *ee, int transparent);
+ void (*fn_profiles_set) (Ecore_Evas *ee, const char **profiles, int num_profiles);
+
+ void (*fn_window_group_set) (Ecore_Evas *ee, const Ecore_Evas *ee_group);
+ void (*fn_aspect_set) (Ecore_Evas *ee, double aspect);
+ void (*fn_urgent_set) (Ecore_Evas *ee, int urgent);
+ void (*fn_modal_set) (Ecore_Evas *ee, int modal);
+ void (*fn_demands_attention_set) (Ecore_Evas *ee, int demand);
+ void (*fn_focus_skip_set) (Ecore_Evas *ee, int skip);
+
+ int (*fn_render) (Ecore_Evas *ee);
+ void (*fn_screen_geometry_get) (const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
+ void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi);
+};
+
+struct _Ecore_Evas_Engine
+{
+ Ecore_Evas_Engine_Func *func;
+
+/* TODO: UGLY! This should be an union or inheritance! */
+#ifdef BUILD_ECORE_EVAS_X11
+ struct
+ {
+ Ecore_X_Window win_root;
+ Eina_List *win_extra;
+ Ecore_X_Pixmap pmap;
+ Ecore_X_Pixmap mask;
+ Ecore_X_GC gc;
+ Ecore_X_XRegion *damages;
+ Ecore_X_Sync_Counter sync_counter;
+ Ecore_X_Window leader;
+ Ecore_X_Sync_Counter netwm_sync_counter;
+ int netwm_sync_val_hi;
+ unsigned int netwm_sync_val_lo;
+ int sync_val; // bigger! this will screw up at 2 billion frames (414 days of continual rendering @ 60fps)
+ int screen_num;
+ int px, py, pw, ph;
+ unsigned char direct_resize : 1;
+ unsigned char using_bg_pixmap : 1;
+ unsigned char managed : 1;
+ unsigned char sync_began : 1;
+ unsigned char sync_cancel : 1;
+ unsigned char netwm_sync_set : 1;
+ unsigned char configure_coming : 1;
+ struct {
+ unsigned char modal : 1;
+ unsigned char sticky : 1;
+ unsigned char maximized_v : 1;
+ unsigned char maximized_h : 1;
+ unsigned char shaded : 1;
+ unsigned char skip_taskbar : 1;
+ unsigned char skip_pager : 1;
+ unsigned char fullscreen : 1;
+ unsigned char above : 1;
+ unsigned char below : 1;
+ } state;
+ Ecore_X_Window win_shaped_input;
+ } x;
+#endif
+#ifdef BUILD_ECORE_EVAS_FB
+ struct {
+ int real_w;
+ int real_h;
+ } fb;
+#endif
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ struct {
+ void *pixels;
+ Evas_Object *image;
+ void (*free_func) (void *data, void *pix);
+ void *(*alloc_func) (void *data, int size);
+ void *data;
+ } buffer;
+#endif
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+ struct {
+ Ecore_DirectFB_Window *window;
+ } directfb;
+#endif
+#ifdef BUILD_ECORE_EVAS_WIN32
+ struct {
+ Ecore_Win32_Window *parent;
+ struct {
+ unsigned char region : 1;
+ unsigned char fullscreen : 1;
+ } state;
+ } win32;
+#endif
+#ifdef BUILD_ECORE_EVAS_EWS
+ struct {
+ Evas_Object *image;
+ } ews;
+#endif
+
+#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL)
+ struct
+ {
+ Ecore_Wl_Window *parent, *win;
+ Evas_Object *frame;
+
+# if defined(BUILD_ECORE_EVAS_WAYLAND_SHM)
+ struct wl_shm_pool *pool;
+ size_t pool_size;
+ void *pool_data;
+ struct wl_buffer *buffer;
+# endif
+
+ } wl;
+#endif
+
+ Ecore_Timer *idle_flush_timer;
+};
+
+struct _Ecore_Evas
+{
+ EINA_INLIST;
+ ECORE_MAGIC;
+ Evas *evas;
+ const char *driver;
+ char *name;
+ int x, y, w, h;
+ short rotation;
+ Eina_Bool shaped : 1;
+ Eina_Bool visible : 1;
+ Eina_Bool draw_ok : 1;
+ Eina_Bool should_be_visible : 1;
+ Eina_Bool alpha : 1;
+ Eina_Bool transparent : 1;
+ Eina_Bool in : 1;
+
+ Eina_Hash *data;
+
+ struct {
+ int x, y, w, h;
+ } req;
+
+ struct {
+ int x, y;
+ } mouse;
+
+ struct {
+ int w, h;
+ } expecting_resize;
+
+ struct {
+ char *title;
+ char *name;
+ char *clas;
+ char *profile;
+ struct {
+ int w, h;
+ } min,
+ max,
+ base,
+ step;
+ struct {
+ Evas_Object *object;
+ int layer;
+ struct {
+ int x, y;
+ } hot;
+ } cursor;
+ int layer;
+ Ecore_Window window;
+ unsigned char avoid_damage;
+ Ecore_Evas *group_ee;
+ Ecore_Window group_ee_win;
+ double aspect;
+ char focused : 1;
+ char iconified : 1;
+ char borderless : 1;
+ char override : 1;
+ char maximized : 1;
+ char fullscreen : 1;
+ char withdrawn : 1;
+ char sticky : 1;
+ char request_pos : 1;
+ char draw_frame : 1;
+ char hwsurface : 1;
+ char urgent : 1;
+ char modal : 1;
+ char demand_attention : 1;
+ char focus_skip : 1;
+ } prop;
+
+ struct {
+ void (*fn_resize) (Ecore_Evas *ee);
+ void (*fn_move) (Ecore_Evas *ee);
+ void (*fn_show) (Ecore_Evas *ee);
+ void (*fn_hide) (Ecore_Evas *ee);
+ void (*fn_delete_request) (Ecore_Evas *ee);
+ void (*fn_destroy) (Ecore_Evas *ee);
+ void (*fn_focus_in) (Ecore_Evas *ee);
+ void (*fn_focus_out) (Ecore_Evas *ee);
+ void (*fn_sticky) (Ecore_Evas *ee);
+ void (*fn_unsticky) (Ecore_Evas *ee);
+ void (*fn_mouse_in) (Ecore_Evas *ee);
+ void (*fn_mouse_out) (Ecore_Evas *ee);
+ void (*fn_pre_render) (Ecore_Evas *ee);
+ void (*fn_post_render) (Ecore_Evas *ee);
+ void (*fn_pre_free) (Ecore_Evas *ee);
+ void (*fn_state_change) (Ecore_Evas *ee);
+ } func;
+
+ Ecore_Evas_Engine engine;
+ Eina_List *sub_ecore_evas;
+
+ int refcount;
+
+ unsigned char ignore_events : 1;
+ unsigned char manual_render : 1;
+ unsigned char registered : 1;
+ unsigned char no_comp_sync : 1;
+ unsigned char semi_sync : 1;
+ unsigned char deleted : 1;
+ int gl_sync_draw_done; // added by gl77.lee
+};
+
+void _ecore_evas_ref(Ecore_Evas *ee);
+void _ecore_evas_unref(Ecore_Evas *ee);
+
+#ifdef BUILD_ECORE_EVAS_X11
+int _ecore_evas_x_shutdown(void);
+#endif
+#ifdef BUILD_ECORE_EVAS_FB
+int _ecore_evas_fb_shutdown(void);
+#endif
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+int _ecore_evas_buffer_shutdown(void);
+int _ecore_evas_buffer_render(Ecore_Evas *ee);
+#endif
+#ifdef BUILD_ECORE_EVAS_DIRECTFB
+int _ecore_evas_directfb_shutdown(void);
+#endif
+#ifdef BUILD_ECORE_EVAS_WIN32
+int _ecore_evas_win32_shutdown(void);
+#endif
+#ifdef BUILD_ECORE_EVAS_EWS
+void _ecore_evas_ews_events_init(void);
+int _ecore_evas_ews_shutdown(void);
+#endif
+
+#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL)
+int _ecore_evas_wl_common_init(void);
+int _ecore_evas_wl_common_shutdown(void);
+void _ecore_evas_wl_common_pre_free(Ecore_Evas *ee);
+void _ecore_evas_wl_common_free(Ecore_Evas *ee);
+void _ecore_evas_wl_common_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee));
+void _ecore_evas_wl_common_move(Ecore_Evas *ee, int x, int y);
+void _ecore_evas_wl_common_raise(Ecore_Evas *ee);
+void _ecore_evas_wl_common_title_set(Ecore_Evas *ee, const char *title);
+void _ecore_evas_wl_common_name_class_set(Ecore_Evas *ee, const char *n, const char *c);
+void _ecore_evas_wl_common_size_min_set(Ecore_Evas *ee, int w, int h);
+void _ecore_evas_wl_common_size_max_set(Ecore_Evas *ee, int w, int h);
+void _ecore_evas_wl_common_size_base_set(Ecore_Evas *ee, int w, int h);
+void _ecore_evas_wl_common_size_step_set(Ecore_Evas *ee, int w, int h);
+void _ecore_evas_wl_common_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y);
+void _ecore_evas_wl_common_layer_set(Ecore_Evas *ee, int layer);
+void _ecore_evas_wl_common_iconified_set(Ecore_Evas *ee, int iconify);
+void _ecore_evas_wl_common_maximized_set(Ecore_Evas *ee, int max);
+void _ecore_evas_wl_common_fullscreen_set(Ecore_Evas *ee, int full);
+void _ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore);
+int _ecore_evas_wl_common_pre_render(Ecore_Evas *ee);
+int _ecore_evas_wl_common_render_updates(Ecore_Evas *ee);
+void _ecore_evas_wl_common_post_render(Ecore_Evas *ee);
+int _ecore_evas_wl_common_render(Ecore_Evas *ee);
+void _ecore_evas_wl_common_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
+void _ecore_evas_wl_common_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi);
+
+Evas_Object * _ecore_evas_wl_common_frame_add(Evas *evas);
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+void _ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location);
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+void _ecore_evas_wayland_egl_resize(Ecore_Evas *ee, int location);
+#endif
+#endif
+
+void _ecore_evas_fps_debug_init(void);
+void _ecore_evas_fps_debug_shutdown(void);
+void _ecore_evas_fps_debug_rendertime_add(double t);
+void _ecore_evas_register(Ecore_Evas *ee);
+void _ecore_evas_free(Ecore_Evas *ee);
+void _ecore_evas_idle_timeout_update(Ecore_Evas *ee);
+void _ecore_evas_mouse_move_process(Ecore_Evas *ee, int x, int y, unsigned int timestamp);
+void _ecore_evas_mouse_multi_move_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ unsigned int timestamp);
+void _ecore_evas_mouse_multi_down_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ Evas_Button_Flags flags,
+ unsigned int timestamp);
+void _ecore_evas_mouse_multi_up_process(Ecore_Evas *ee, int device,
+ int x, int y,
+ double radius,
+ double radius_x, double radius_y,
+ double pressure,
+ double angle,
+ double mx, double my,
+ Evas_Button_Flags flags,
+ unsigned int timestamp);
+
+extern Eina_Bool _ecore_evas_app_comp_sync;
+
+void _ecore_evas_extn_init(void);
+void _ecore_evas_extn_shutdown(void);
+
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_psl1ght.c b/src/lib/ecore_evas/ecore_evas_psl1ght.c
new file mode 100644
index 0000000000..35252a3703
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_psl1ght.c
@@ -0,0 +1,515 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <Ecore_Input_Evas.h>
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_PSL1GHT
+#include <Ecore_Psl1ght.h>
+#include <Evas_Engine_PSL1GHT.h>
+
+static int _ecore_evas_init_count = 0;
+
+static Ecore_Evas *psl1ght_ee = NULL;
+static Ecore_Event_Handler *ecore_evas_event_handlers[5] = {
+ NULL, NULL, NULL, NULL
+};
+
+static const char *ecore_evas_psl1ght_default = "EFL PSL1GHT";
+static int _ecore_evas_fps_debug = 0;
+static Ecore_Poller *ecore_evas_event;
+
+static unsigned int
+_ecore_evas_time_get()
+{
+ return (unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff;
+}
+
+static Ecore_Evas *
+_ecore_evas_psl1ght_match(void)
+{
+ return psl1ght_ee;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event_got_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = _ecore_evas_psl1ght_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ /* pass on event */
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event_lost_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = _ecore_evas_psl1ght_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ /* pass on event */
+ evas_focus_out(ee->evas);
+ ee->prop.focused = 0;
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event_video_expose(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ int w;
+ int h;
+
+ ee = _ecore_evas_psl1ght_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ evas_output_size_get(ee->evas, &w, &h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, w, h);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event_key_modifiers(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Psl1ght_Event_Key_Modifiers *e = event;
+
+ ee = _ecore_evas_psl1ght_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event_quit (void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = _ecore_evas_psl1ght_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (ee->func.fn_delete_request)
+ ee->func.fn_delete_request(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_render(Ecore_Evas *ee)
+{
+ Eina_List *updates;
+
+ updates = evas_render_updates(ee->evas);
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ }
+ return updates ? 1 : 0;
+}
+
+static int
+_ecore_evas_psl1ght_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ rend |= _ecore_evas_buffer_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+#endif
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+ if (ee->prop.avoid_damage) rend = _ecore_evas_render(ee);
+ else if ((ee->visible) ||
+ ((ee->should_be_visible) && (ee->prop.fullscreen)) ||
+ ((ee->should_be_visible) && (ee->prop.override)))
+ rend |= _ecore_evas_render(ee);
+ else
+ evas_norender(ee->evas);
+
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ return rend;
+}
+
+static Eina_Bool
+_ecore_evas_psl1ght_event(void *data EINA_UNUSED)
+{
+ ecore_psl1ght_poll_events();
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int
+_ecore_evas_psl1ght_init(int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+
+ _ecore_evas_fps_debug = 1;
+
+ // this is pretty bad: poller? and set poll time? pol time is meant to be
+ // adjustable for things like polling battery state, or amoutn of spare
+ // memory etc.
+ //
+ ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_evas_psl1ght_event, NULL);
+ ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006);
+
+ if (_ecore_evas_fps_debug)
+ _ecore_evas_fps_debug_init();
+
+ ecore_event_evas_init();
+
+ ecore_evas_event_handlers[0] =
+ ecore_event_handler_add(ECORE_PSL1GHT_EVENT_GOT_FOCUS,
+ _ecore_evas_psl1ght_event_got_focus, NULL);
+ ecore_evas_event_handlers[1] =
+ ecore_event_handler_add(ECORE_PSL1GHT_EVENT_LOST_FOCUS,
+ _ecore_evas_psl1ght_event_lost_focus, NULL);
+ ecore_evas_event_handlers[2] =
+ ecore_event_handler_add(ECORE_PSL1GHT_EVENT_EXPOSE,
+ _ecore_evas_psl1ght_event_video_expose, NULL);
+ ecore_evas_event_handlers[3] =
+ ecore_event_handler_add(ECORE_PSL1GHT_EVENT_KEY_MODIFIERS,
+ _ecore_evas_psl1ght_event_key_modifiers, NULL);
+ ecore_evas_event_handlers[4] =
+ ecore_event_handler_add(ECORE_PSL1GHT_EVENT_QUIT,
+ _ecore_evas_psl1ght_event_quit, NULL);
+
+ return _ecore_evas_init_count;
+}
+
+static int
+_ecore_evas_psl1ght_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler *); i++)
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ ecore_event_evas_shutdown();
+ ecore_poller_del(ecore_evas_event);
+ ecore_evas_event = NULL;
+ if (_ecore_evas_fps_debug)
+ _ecore_evas_fps_debug_shutdown();
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_psl1ght_free(Ecore_Evas *ee)
+{
+ if (psl1ght_ee == ee) psl1ght_ee = NULL;
+
+ ecore_event_window_unregister(0);
+ _ecore_evas_psl1ght_shutdown();
+ ecore_psl1ght_shutdown();
+}
+
+static void
+_ecore_evas_psl1ght_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ ee->func.fn_delete_request = func;
+}
+
+static void
+_ecore_evas_screen_resized(Ecore_Evas *ee)
+{
+ int w, h;
+
+ /* Do not resize if the window is not fullscreen */
+ if (ee->prop.fullscreen == 0) return;
+
+ ecore_psl1ght_screen_resolution_get (&w, &h);
+
+ if (w != ee->w || h != ee->h)
+ {
+ ee->req.w = ee->w = w;
+ ee->req.h = ee->h = h;
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ ecore_psl1ght_resolution_set (w, h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ _ecore_evas_time_get());
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->w = w;
+ ee->h = h;
+
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ ecore_psl1ght_resolution_set (w, h);
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+
+ _ecore_evas_screen_resized (ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ _ecore_evas_resize (ee, w, h);
+}
+
+static void
+_ecore_evas_show(Ecore_Evas *ee)
+{
+ if (ee->prop.focused) return;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+}
+
+static void
+_ecore_evas_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h)
+{
+ if (x) *x = 0;
+ if (y) *y = 0;
+ ecore_psl1ght_screen_resolution_get (w, h);
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee)
+ ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+static Ecore_Evas_Engine_Func _ecore_psl1ght_engine_func =
+{
+ _ecore_evas_psl1ght_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_psl1ght_callback_delete_request_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ NULL,
+ NULL,
+ _ecore_evas_show,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_object_cursor_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ _ecore_evas_screen_geometry_get, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+
+EAPI Ecore_Evas *
+ecore_evas_psl1ght_new(const char *name, int w, int h)
+{
+ void *einfo;
+ Ecore_Evas *ee;
+
+ if (!name)
+ name = ecore_evas_psl1ght_default;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_psl1ght_engine_func;
+
+ ee->driver = "psl1ght";
+ if (name) ee->name = strdup(name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->visible = 1;
+ ee->w = w;
+ ee->h = h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 1;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 1;
+ ee->prop.fullscreen = 0;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+ ee->prop.window = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, evas_render_method_lookup("psl1ght"));
+
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ einfo = evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ if (!ecore_psl1ght_init(name))
+ {
+ evas_free(ee->evas);
+ if (ee->name) free(ee->name);
+ free(ee);
+ return NULL;
+ }
+ ecore_psl1ght_resolution_set (w, h);
+
+ _ecore_evas_psl1ght_init(w, h);
+
+ ecore_event_window_register(0, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ ee->engine.func->fn_render = _ecore_evas_psl1ght_render;
+ _ecore_evas_register(ee);
+
+ psl1ght_ee = ee;
+
+ _ecore_evas_screen_resized (ee);
+
+ if (getenv("ECORE_EVAS_PSL1GHT_CURSOR_PATH"))
+ ecore_evas_cursor_set(ee, getenv("ECORE_EVAS_PSL1GHT_CURSOR_PATH"), EVAS_LAYER_MAX, 0, 0);
+
+ evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
+
+ return ee;
+}
+
+#else /* BUILD_ECORE_EVAS_PSL1GHT */
+
+EAPI Ecore_Evas *
+ecore_evas_psl1ght_new(const char *name EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ ERR("OUTCH !");
+ return NULL;
+}
+
+#endif /* BUILD_ECORE_EVAS_PSL1GHT */
diff --git a/src/lib/ecore_evas/ecore_evas_sdl.c b/src/lib/ecore_evas/ecore_evas_sdl.c
new file mode 100644
index 0000000000..90b348ef2c
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_sdl.c
@@ -0,0 +1,665 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <Ecore_Input_Evas.h>
+#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL)
+# include <Ecore_Sdl.h>
+# ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+# include <Evas_Engine_GL_SDL.h>
+# endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL)
+#include <SDL/SDL.h>
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+/*
+ * SDL only handle one window at a time. That's by definition, there is nothing wrong here.
+ *
+ */
+#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL)
+
+/* static char *ecore_evas_default_display = "0"; */
+/* static Ecore_List *ecore_evas_input_devices = NULL; */
+
+static int _ecore_evas_init_count = 0;
+
+static Ecore_Evas *sdl_ee = NULL;
+static Ecore_Event_Handler *ecore_evas_event_handlers[4] = {
+ NULL, NULL, NULL, NULL
+};
+
+static const char *ecore_evas_sdl_default = "EFL SDL";
+static int _ecore_evas_fps_debug = 0;
+static Ecore_Poller *ecore_evas_event;
+
+static Ecore_Evas *
+_ecore_evas_sdl_match(void)
+{
+ return sdl_ee;
+}
+
+static void *
+_ecore_evas_sdl_switch_buffer(void *data, void *dest EINA_UNUSED)
+{
+ SDL_Flip(data);
+ return ((SDL_Surface*)data)->pixels;
+}
+
+static Eina_Bool
+_ecore_evas_sdl_event_got_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = _ecore_evas_sdl_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ /* pass on event */
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_sdl_event_lost_focus(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = _ecore_evas_sdl_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ /* pass on event */
+ ee->prop.focused = 0;
+ evas_focus_out(ee->evas);
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_sdl_event_video_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Sdl_Event_Video_Resize *e;
+ Ecore_Evas *ee;
+ int rmethod;
+
+ e = event;
+ ee = _ecore_evas_sdl_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+
+ rmethod = evas_output_method_get(ee->evas);
+ if (rmethod == evas_render_method_lookup("buffer"))
+ {
+ Evas_Engine_Info_Buffer *einfo;
+
+ einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.switch_data = SDL_SetVideoMode(e->w, e->h, 32,
+ (ee->prop.hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE)
+ | (ee->prop.fullscreen ? SDL_FULLSCREEN : 0)
+ | (ee->alpha ? SDL_SRCALPHA : 0)
+ | SDL_DOUBLEBUF);
+ if (!einfo->info.switch_data)
+ {
+ return EINA_FALSE;
+ }
+
+ SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0);
+ SDL_FillRect(einfo->info.switch_data, NULL, 0);
+
+ einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels;
+ einfo->info.dest_buffer_row_bytes = e->w * sizeof (int);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo))
+ {
+ return EINA_FALSE;
+ }
+ }
+ }
+
+ ee->w = e->w;
+ ee->h = e->h;
+ ee->req.w = e->w;
+ ee->req.h = e->h;
+
+ evas_output_size_set(ee->evas, e->w, e->h);
+ evas_output_viewport_set(ee->evas, 0, 0, e->w, e->h);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_sdl_event_video_expose(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+ int w;
+ int h;
+
+ ee = _ecore_evas_sdl_match();
+
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ evas_output_size_get(ee->evas, &w, &h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, w, h);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static int
+_ecore_evas_render(Ecore_Evas *ee)
+{
+ Eina_List *updates;
+
+ updates = evas_render_updates(ee->evas);
+ if (updates)
+ {
+ evas_render_updates_free(updates);
+ _ecore_evas_idle_timeout_update(ee);
+ }
+ return updates ? 1 : 0;
+}
+
+static int
+_ecore_evas_sdl_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+ if (ee->prop.avoid_damage) rend = _ecore_evas_render(ee);
+ else if ((ee->visible) ||
+ ((ee->should_be_visible) && (ee->prop.fullscreen)) ||
+ ((ee->should_be_visible) && (ee->prop.override)))
+ rend |= _ecore_evas_render(ee);
+ else
+ evas_norender(ee->evas);
+
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ return rend;
+}
+
+static Eina_Bool
+_ecore_evas_sdl_event(void *data EINA_UNUSED)
+{
+ ecore_sdl_feed_events();
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int
+_ecore_evas_sdl_init(int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+
+#ifndef _WIN32
+ if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1;
+#endif /* _WIN32 */
+ // this is pretty bad: poller? and set poll time? pol time is meant to be
+ // adjustable for things like polling battery state, or amoutn of spare
+ // memory etc.
+ //
+ ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_evas_sdl_event, NULL);
+ ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006);
+#ifndef _WIN32
+ if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init();
+#endif /* _WIN32 */
+
+ ecore_event_evas_init();
+
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_SDL_EVENT_GOT_FOCUS, _ecore_evas_sdl_event_got_focus, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_SDL_EVENT_LOST_FOCUS, _ecore_evas_sdl_event_lost_focus, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_SDL_EVENT_RESIZE, _ecore_evas_sdl_event_video_resize, NULL);
+ ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_SDL_EVENT_EXPOSE, _ecore_evas_sdl_event_video_expose, NULL);
+
+ return _ecore_evas_init_count;
+}
+
+static int
+_ecore_evas_sdl_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler*); i++)
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ ecore_event_evas_shutdown();
+ ecore_poller_del(ecore_evas_event);
+ ecore_evas_event = NULL;
+#ifndef _WIN32
+ if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown();
+#endif /* _WIN32 */
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_sdl_free(Ecore_Evas *ee)
+{
+ if (sdl_ee == ee) sdl_ee = NULL;
+
+ ecore_event_window_unregister(0);
+ _ecore_evas_sdl_shutdown();
+ ecore_sdl_shutdown();
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee, int w, int h)
+{
+ int rmethod;
+
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->req.w = w;
+ ee->req.h = h;
+ ee->w = w;
+ ee->h = h;
+
+ rmethod = evas_output_method_get(ee->evas);
+ if (rmethod == evas_render_method_lookup("buffer"))
+ {
+ Evas_Engine_Info_Buffer *einfo;
+
+ einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.switch_data = SDL_SetVideoMode(w, h, 32,
+ (ee->prop.hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE)
+ | (ee->prop.fullscreen ? SDL_FULLSCREEN : 0)
+ | (ee->alpha ? SDL_SRCALPHA : 0)
+ | SDL_DOUBLEBUF);
+ if (!einfo->info.switch_data)
+ {
+ return ;
+ }
+
+ SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0);
+ SDL_FillRect(einfo->info.switch_data, NULL, 0);
+
+ einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels;
+ einfo->info.dest_buffer_row_bytes = w * sizeof (int);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo))
+ {
+ return ;
+ }
+ }
+ }
+
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_move_resize(Ecore_Evas *ee, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h)
+{
+ if ((w == ee->w) && (h == ee->h)) return;
+ ee->req.w = w;
+ ee->req.h = h;
+ ee->w = w;
+ ee->h = h;
+
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void
+_ecore_evas_show(Ecore_Evas *ee)
+{
+ if (ee->prop.focused) return;
+ ee->prop.focused = 1;
+ evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee) ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+static Ecore_Evas_Engine_Func _ecore_sdl_engine_func =
+{
+ _ecore_evas_sdl_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_resize,
+ _ecore_evas_move_resize,
+ NULL,
+ NULL,
+ _ecore_evas_show,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_object_cursor_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL, // screen_geometry_get
+ NULL // screen_dpi_get
+};
+
+static Ecore_Evas*
+_ecore_evas_internal_sdl_new(int rmethod, const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha)
+{
+ Ecore_Evas *ee;
+
+ if (!name)
+ name = ecore_evas_sdl_default;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_sdl_engine_func;
+
+ ee->driver = "sdl";
+ if (name) ee->name = strdup(name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->visible = 1;
+ ee->req.w = w;
+ ee->req.h = h;
+ ee->w = w;
+ ee->h = h;
+
+ ee->prop.max.w = 0;
+ ee->prop.max.h = 0;
+ ee->prop.layer = 0;
+ ee->prop.focused = 1;
+ ee->prop.borderless = 1;
+ ee->prop.override = 1;
+ ee->prop.maximized = 1;
+ ee->prop.fullscreen = fullscreen;
+ ee->prop.withdrawn = 0;
+ ee->prop.sticky = 0;
+ ee->prop.window = 0;
+ ee->alpha = alpha;
+ ee->prop.hwsurface = hwsurface;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ if (rmethod == evas_render_method_lookup("buffer"))
+ {
+ Evas_Engine_Info_Buffer *einfo;
+
+ einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ SDL_Init(SDL_INIT_NOPARACHUTE);
+
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
+ {
+ ERR("SDL_Init failed with %s", SDL_GetError());
+ SDL_Quit();
+ return NULL;
+ }
+
+ einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32;
+ einfo->info.switch_data = SDL_SetVideoMode(w, h, 32,
+ (hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE)
+ | (fullscreen ? SDL_FULLSCREEN : 0)
+ | (noframe ? SDL_NOFRAME : 0)
+ | (alpha ? SDL_SRCALPHA : 0)
+ | SDL_DOUBLEBUF);
+ if (!einfo->info.switch_data)
+ {
+ ERR("SDL_SetVideoMode failed !");
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0);
+ SDL_FillRect(einfo->info.switch_data, NULL, 0);
+
+ einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels;
+ einfo->info.dest_buffer_row_bytes = w * sizeof (int);
+ einfo->info.use_color_key = 0;
+ einfo->info.alpha_threshold = 0;
+ einfo->info.func.new_update_region = NULL;
+ einfo->info.func.free_update_region = NULL;
+ einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else if (rmethod == evas_render_method_lookup("gl_sdl"))
+ {
+#ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+ Evas_Engine_Info_GL_SDL *einfo;
+
+ einfo = (Evas_Engine_Info_GL_SDL *) evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->flags.fullscreen = fullscreen;
+ einfo->flags.noframe = noframe;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+#endif
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+
+ if (!ecore_sdl_init(name))
+ {
+ evas_free(ee->evas);
+ if (ee->name) free(ee->name);
+ free(ee);
+ return NULL;
+ }
+
+ _ecore_evas_sdl_init(w, h);
+
+ ecore_event_window_register(0, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ SDL_ShowCursor(SDL_ENABLE);
+
+ ee->engine.func->fn_render = _ecore_evas_sdl_render;
+ _ecore_evas_register(ee);
+
+ sdl_ee = ee;
+ return ee;
+}
+#endif
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL
+EAPI Ecore_Evas*
+ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha)
+{
+ Ecore_Evas *ee;
+ int rmethod;
+
+ rmethod = evas_render_method_lookup("buffer");
+ if (!rmethod) return NULL;
+
+ ee = _ecore_evas_internal_sdl_new(rmethod, name, w, h, fullscreen, hwsurface, noframe, alpha);
+ return ee;
+}
+#else
+EAPI Ecore_Evas*
+ecore_evas_sdl_new(const char* name EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, int fullscreen EINA_UNUSED, int hwsurface EINA_UNUSED, int noframe EINA_UNUSED, int alpha EINA_UNUSED)
+{
+ ERR("OUTCH !");
+ return NULL;
+}
+#endif
+
+EAPI Ecore_Evas*
+ecore_evas_sdl16_new(const char* name EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, int fullscreen EINA_UNUSED, int hwsurface EINA_UNUSED, int noframe EINA_UNUSED, int alpha EINA_UNUSED)
+{
+ ERR("OUTCH !");
+ return NULL;
+}
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_SDL
+EAPI Ecore_Evas*
+ecore_evas_gl_sdl_new(const char* name, int w, int h, int fullscreen, int noframe)
+{
+ Ecore_Evas *ee;
+ int rmethod;
+
+ rmethod = evas_render_method_lookup("gl_sdl");
+ if (!rmethod) return NULL;
+
+ ee = _ecore_evas_internal_sdl_new(rmethod, name, w, h, fullscreen, 0, noframe, 0);
+ if (ee) ee->driver = "gl_sdl";
+ return ee;
+}
+#else
+EAPI Ecore_Evas*
+ecore_evas_gl_sdl_new(const char* name EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, int fullscreen EINA_UNUSED, int noframe EINA_UNUSED)
+{
+ ERR("OUTCH !");
+ return NULL;
+}
+#endif
+
diff --git a/src/lib/ecore_evas/ecore_evas_util.c b/src/lib/ecore_evas/ecore_evas_util.c
new file mode 100644
index 0000000000..85ff2bd37f
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_util.c
@@ -0,0 +1,451 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <Ecore.h>
+#include "ecore_private.h"
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+static const char ASSOCIATE_KEY[] = "__Ecore_Evas_Associate";
+
+static void _ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags);
+static void _ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj);
+
+
+static Evas_Object *
+_ecore_evas_associate_get(const Ecore_Evas *ee)
+{
+ return ecore_evas_data_get(ee, ASSOCIATE_KEY);
+}
+
+static void
+_ecore_evas_associate_set(Ecore_Evas *ee, Evas_Object *obj)
+{
+ ecore_evas_data_set(ee, ASSOCIATE_KEY, obj);
+}
+
+static void
+_ecore_evas_associate_del(Ecore_Evas *ee)
+{
+ ecore_evas_data_set(ee, ASSOCIATE_KEY, NULL);
+}
+
+static Ecore_Evas *
+_evas_object_associate_get(const Evas_Object *obj)
+{
+ return evas_object_data_get(obj, ASSOCIATE_KEY);
+}
+
+static void
+_evas_object_associate_set(Evas_Object *obj, Ecore_Evas *ee)
+{
+ evas_object_data_set(obj, ASSOCIATE_KEY, ee);
+}
+
+static void
+_evas_object_associate_del(Evas_Object *obj)
+{
+ evas_object_data_del(obj, ASSOCIATE_KEY);
+}
+
+/** Associated Events: ******************************************************/
+
+/* Interceptors Callbacks */
+
+static void
+_ecore_evas_obj_intercept_move(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+ Ecore_Evas *ee = data;
+ // FIXME: account for frame
+ ecore_evas_move(ee, x, y);
+ if (ecore_evas_override_get(ee)) evas_object_move(obj, x, y);
+}
+
+static void
+_ecore_evas_obj_intercept_raise(void *data, Evas_Object *obj EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_raise(ee);
+}
+
+static void
+_ecore_evas_obj_intercept_lower(void *data, Evas_Object *obj EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_lower(ee);
+}
+
+static void
+_ecore_evas_obj_intercept_stack_above(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Object *above EINA_UNUSED)
+{
+ INF("TODO: %s", __FUNCTION__);
+}
+
+static void
+_ecore_evas_obj_intercept_stack_below(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Object *below EINA_UNUSED)
+{
+ INF("TODO: %s", __FUNCTION__);
+}
+
+static void
+_ecore_evas_obj_intercept_layer_set(void *data, Evas_Object *obj EINA_UNUSED, int l)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_layer_set(ee, l);
+}
+
+/* Event Callbacks */
+
+static void
+_ecore_evas_obj_callback_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_show(ee);
+}
+
+static void
+_ecore_evas_obj_callback_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ ecore_evas_hide(ee);
+}
+
+static void
+_ecore_evas_obj_callback_resize(void *data, Evas *e, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Coord ow, oh, fw, fh;
+
+ evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+ evas_output_framespace_get(e, NULL, NULL, &fw, &fh);
+ ow += fw;
+ oh += fh;
+ ecore_evas_resize(ee, ow, oh);
+}
+
+static void
+_ecore_evas_obj_callback_changed_size_hints(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Evas_Coord w, h;
+
+ evas_object_size_hint_min_get(obj, &w, &h);
+ ecore_evas_size_min_set(ee, w, h);
+
+ evas_object_size_hint_max_get(obj, &w, &h);
+ if (w < 1) w = -1;
+ if (h < 1) h = -1;
+ ecore_evas_size_max_set(ee, w, h);
+}
+
+static void
+_ecore_evas_obj_callback_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ _ecore_evas_object_dissociate(ee, obj);
+ ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_obj_callback_del_dissociate(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ _ecore_evas_object_dissociate(ee, obj);
+}
+
+static void
+_ecore_evas_delete_request(Ecore_Evas *ee)
+{
+ Evas_Object *obj = _ecore_evas_associate_get(ee);
+ _ecore_evas_object_dissociate(ee, obj);
+ evas_object_del(obj);
+ ecore_evas_free(ee);
+}
+
+static void
+_ecore_evas_destroy(Ecore_Evas *ee)
+{
+ Evas_Object *obj = _ecore_evas_associate_get(ee);
+ if (!obj)
+ return;
+ _ecore_evas_object_dissociate(ee, obj);
+ evas_object_del(obj);
+}
+
+static void
+_ecore_evas_resize(Ecore_Evas *ee)
+{
+ Evas_Object *obj = _ecore_evas_associate_get(ee);
+ Evas_Coord w, h;
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ evas_object_resize(obj, w, h);
+}
+
+static void
+_ecore_evas_pre_free(Ecore_Evas *ee)
+{
+ Evas_Object *obj = _ecore_evas_associate_get(ee);
+ if (!obj)
+ return;
+ _ecore_evas_object_dissociate(ee, obj);
+ evas_object_del(obj);
+}
+
+static int
+_ecore_evas_object_evas_check(const char *function EINA_UNUSED, const Ecore_Evas *ee, const Evas_Object *obj)
+{
+ const char *name, *type;
+ Evas *e;
+
+ e = evas_object_evas_get(obj);
+ if (e == ee->evas)
+ return 1;
+
+ name = evas_object_name_get(obj);
+ type = evas_object_type_get(obj);
+
+ ERR("ERROR: %s(): object %p (name=\"%s\", type=\"%s\") evas "
+ "is not the same as this Ecore_Evas evas: %p != %p",
+ function, obj,
+ name ? name : "", type ? type : "", e, ee->evas);
+ fflush(stderr);
+ if (getenv("ECORE_ERROR_ABORT")) abort();
+
+ return 0;
+}
+
+EAPI Eina_Bool
+ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
+{
+ Ecore_Evas *old_ee;
+ Evas_Object *old_obj;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+ return EINA_FALSE;
+ }
+
+ CHECK_PARAM_POINTER_RETURN("obj", obj, EINA_FALSE);
+ if (!_ecore_evas_object_evas_check(__FUNCTION__, ee, obj))
+ return EINA_FALSE;
+
+ old_ee = _evas_object_associate_get(obj);;
+ if (old_ee)
+ ecore_evas_object_dissociate(old_ee, obj);
+
+ old_obj = _ecore_evas_associate_get(ee);
+ if (old_obj)
+ ecore_evas_object_dissociate(ee, old_obj);
+
+ _ecore_evas_object_associate(ee, obj, flags);
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
+{
+ Ecore_Evas *old_ee;
+ Evas_Object *old_obj;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+ return EINA_FALSE;
+ }
+
+ CHECK_PARAM_POINTER_RETURN("obj", obj, EINA_FALSE);
+ old_ee = _evas_object_associate_get(obj);
+ if (ee != old_ee) {
+ ERR("ERROR: trying to dissociate object that is not using "
+ "this Ecore_Evas: %p != %p", ee, old_ee);
+ return EINA_FALSE;
+ }
+
+ old_obj = _ecore_evas_associate_get(ee);
+ if (old_obj != obj) {
+ ERR("ERROR: trying to dissociate object that is not being "
+ "used by this Ecore_Evas: %p != %p", old_obj, obj);
+ return EINA_FALSE;
+ }
+
+ _ecore_evas_object_dissociate(ee, obj);
+
+ return EINA_TRUE;
+}
+
+EAPI Evas_Object *
+ecore_evas_object_associate_get(const Ecore_Evas *ee)
+{
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+ return NULL;
+ }
+ return _ecore_evas_associate_get(ee);
+}
+
+static void
+_ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags)
+{
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_SHOW,
+ _ecore_evas_obj_callback_show, ee);
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_HIDE,
+ _ecore_evas_obj_callback_hide, ee);
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_RESIZE,
+ _ecore_evas_obj_callback_resize, ee);
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+ _ecore_evas_obj_callback_changed_size_hints, ee);
+ if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL)
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
+ else
+ evas_object_event_callback_add
+ (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee);
+
+ evas_object_intercept_move_callback_add
+ (obj, _ecore_evas_obj_intercept_move, ee);
+
+ if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_STACK)
+ {
+ evas_object_intercept_raise_callback_add
+ (obj, _ecore_evas_obj_intercept_raise, ee);
+ evas_object_intercept_lower_callback_add
+ (obj, _ecore_evas_obj_intercept_lower, ee);
+ evas_object_intercept_stack_above_callback_add
+ (obj, _ecore_evas_obj_intercept_stack_above, ee);
+ evas_object_intercept_stack_below_callback_add
+ (obj, _ecore_evas_obj_intercept_stack_below, ee);
+ }
+
+ if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_LAYER)
+ evas_object_intercept_layer_set_callback_add
+ (obj, _ecore_evas_obj_intercept_layer_set, ee);
+
+ if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL)
+ {
+ ecore_evas_callback_delete_request_set(ee, _ecore_evas_delete_request);
+ ecore_evas_callback_destroy_set(ee, _ecore_evas_destroy);
+ }
+ ecore_evas_callback_pre_free_set(ee, _ecore_evas_pre_free);
+ ecore_evas_callback_resize_set(ee, _ecore_evas_resize);
+
+ _evas_object_associate_set(obj, ee);
+ _ecore_evas_associate_set(ee, obj);
+}
+
+static void
+_ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj)
+{
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_SHOW,
+ _ecore_evas_obj_callback_show, ee);
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_HIDE,
+ _ecore_evas_obj_callback_hide, ee);
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_RESIZE,
+ _ecore_evas_obj_callback_resize, ee);
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+ _ecore_evas_obj_callback_changed_size_hints, ee);
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee);
+ evas_object_event_callback_del_full
+ (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee);
+
+ evas_object_intercept_move_callback_del
+ (obj, _ecore_evas_obj_intercept_move);
+
+ evas_object_intercept_raise_callback_del
+ (obj, _ecore_evas_obj_intercept_raise);
+ evas_object_intercept_lower_callback_del
+ (obj, _ecore_evas_obj_intercept_lower);
+ evas_object_intercept_stack_above_callback_del
+ (obj, _ecore_evas_obj_intercept_stack_above);
+ evas_object_intercept_stack_below_callback_del
+ (obj, _ecore_evas_obj_intercept_stack_below);
+
+ evas_object_intercept_layer_set_callback_del
+ (obj, _ecore_evas_obj_intercept_layer_set);
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__);
+ }
+ else
+ {
+ if (ee->func.fn_delete_request == _ecore_evas_delete_request)
+ ecore_evas_callback_delete_request_set(ee, NULL);
+ if (ee->func.fn_destroy == _ecore_evas_destroy)
+ ecore_evas_callback_destroy_set(ee, NULL);
+ if (ee->func.fn_resize == _ecore_evas_resize)
+ ecore_evas_callback_resize_set(ee, NULL);
+ if (ee->func.fn_pre_free == _ecore_evas_pre_free)
+ ecore_evas_callback_pre_free_set(ee, NULL);
+
+ _ecore_evas_associate_del(ee);
+ }
+
+ _evas_object_associate_del(obj);
+}
+
+/**
+ * Helper ecore_getopt callback to list available Ecore_Evas engines.
+ *
+ * This will list all available engines except buffer, this is useful
+ * for applications to let user choose how they should create windows
+ * with ecore_evas_new().
+ *
+ * @c callback_data value is used as @c FILE* and says where to output
+ * messages, by default it is @c stdout. You can specify this value
+ * with ECORE_GETOPT_CALLBACK_FULL() or ECORE_GETOPT_CALLBACK_ARGS().
+ *
+ * If there is a boolean storage provided, then it is marked with 1
+ * when this option is executed.
+ * @param parser This parameter isn't in use.
+ * @param desc This parameter isn't in use.
+ * @param str This parameter isn't in use.
+ * @param data The data to be used.
+ * @param storage The storage to be used.
+ * @return The function always return 1.
+ */
+unsigned char
+ecore_getopt_callback_ecore_evas_list_engines(const Ecore_Getopt *parser EINA_UNUSED, const Ecore_Getopt_Desc *desc EINA_UNUSED, const char *str EINA_UNUSED, void *data, Ecore_Getopt_Value *storage)
+{
+ Eina_List *lst, *n;
+ const char *engine;
+
+ if (!storage)
+ {
+ ERR("Storage is missing");
+ return 0;
+ }
+
+ FILE *fp = data;
+ if (!fp)
+ fp = stdout;
+
+ lst = ecore_evas_engines_get();
+
+ fputs("supported engines:\n", fp);
+ EINA_LIST_FOREACH(lst, n, engine)
+ if (strcmp(engine, "buffer") != 0)
+ fprintf(fp, "\t%s\n", engine);
+
+ ecore_evas_engines_free(lst);
+
+ if (storage->boolp)
+ *storage->boolp = 1;
+
+ return 1;
+}
diff --git a/src/lib/ecore_evas/ecore_evas_wayland_common.c b/src/lib/ecore_evas/ecore_evas_wayland_common.c
new file mode 100644
index 0000000000..f29e711166
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_wayland_common.c
@@ -0,0 +1,785 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+//#define LOGFNS 1
+
+#ifdef LOGFNS
+# include <stdio.h>
+# define LOGFN(fl, ln, fn) \
+ printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn);
+#else
+# define LOGFN(fl, ln, fn)
+#endif
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+/* local structures */
+typedef struct _EE_Wl_Smart_Data EE_Wl_Smart_Data;
+struct _EE_Wl_Smart_Data
+{
+ Evas_Object *frame;
+ Evas_Object *text;
+ Evas_Coord x, y, w, h;
+};
+
+static Evas_Smart *_ecore_evas_wl_common_smart = NULL;
+
+/* local variables */
+
+static int _ecore_evas_wl_init_count = 0;
+static Ecore_Event_Handler *_ecore_evas_wl_event_hdls[5];
+
+static Eina_Bool
+_ecore_evas_wl_common_cb_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Event_Mouse_In *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = event;
+ ee = ecore_event_window_match(ev->window);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (!ee->in)
+ {
+ if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee);
+ ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers);
+ evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL);
+ ee->in = EINA_TRUE;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_wl_common_cb_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Event_Mouse_Out *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = event;
+ ee = ecore_event_window_match(ev->window);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->in)
+ {
+ ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers);
+ evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+ ee->in = EINA_FALSE;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_wl_common_cb_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Event_Focus_In *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = event;
+ ee = ecore_event_window_match(ev->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_wl_common_cb_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Event_Focus_In *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = event;
+ ee = ecore_event_window_match(ev->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ evas_focus_out(ee->evas);
+ ee->prop.focused = 0;
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_wl_common_cb_window_configure(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Event_Window_Configure *ev;
+ int nw = 0, nh = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = event;
+ ee = ecore_event_window_match(ev->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON;
+ if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+
+ if (ee->prop.fullscreen)
+ {
+ _ecore_evas_wl_common_move(ee, ev->x, ev->y);
+ ee->engine.func->fn_resize(ee, ev->w, ev->h);
+
+ return ECORE_CALLBACK_PASS_ON;
+ }
+
+ if ((ee->x != ev->x) || (ee->y != ev->y))
+ {
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+
+ nw = ev->w;
+ nh = ev->h;
+
+ if ((ee->prop.maximized) || (!ee->prop.fullscreen))
+ {
+ int fw = 0, fh = 0;
+
+ evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
+ nw = ev->w - fw;
+ nh = ev->h - fh;
+ }
+
+ if (ee->prop.min.w > nw) nw = ee->prop.min.w;
+ else if (nw > ee->prop.max.w) nw = ee->prop.max.w;
+ if (ee->prop.min.h > nh) nh = ee->prop.min.h;
+ else if (nh > ee->prop.max.h) nh = ee->prop.max.h;
+
+ if ((ee->w != nw) || (ee->h != nh))
+ {
+ ee->req.w = nw;
+ ee->req.h = nh;
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+int
+_ecore_evas_wl_common_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (++_ecore_evas_wl_init_count != 1)
+ return _ecore_evas_wl_init_count;
+
+ _ecore_evas_wl_event_hdls[0] =
+ ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_IN,
+ _ecore_evas_wl_common_cb_mouse_in, NULL);
+ _ecore_evas_wl_event_hdls[1] =
+ ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT,
+ _ecore_evas_wl_common_cb_mouse_out, NULL);
+ _ecore_evas_wl_event_hdls[2] =
+ ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN,
+ _ecore_evas_wl_common_cb_focus_in, NULL);
+ _ecore_evas_wl_event_hdls[3] =
+ ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT,
+ _ecore_evas_wl_common_cb_focus_out, NULL);
+ _ecore_evas_wl_event_hdls[4] =
+ ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE,
+ _ecore_evas_wl_common_cb_window_configure, NULL);
+
+ ecore_event_evas_init();
+
+ return _ecore_evas_wl_init_count;
+}
+
+int
+_ecore_evas_wl_common_shutdown(void)
+{
+ unsigned int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (--_ecore_evas_wl_init_count != 0)
+ return _ecore_evas_wl_init_count;
+
+ for (i = 0; i < sizeof(_ecore_evas_wl_event_hdls) / sizeof(Ecore_Event_Handler *); i++)
+ {
+ if (_ecore_evas_wl_event_hdls[i])
+ ecore_event_handler_del(_ecore_evas_wl_event_hdls[i]);
+ }
+
+ ecore_event_evas_shutdown();
+
+ return _ecore_evas_wl_init_count;
+}
+
+void
+_ecore_evas_wl_common_pre_free(Ecore_Evas *ee)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->engine.wl.frame) evas_object_del(ee->engine.wl.frame);
+}
+
+void
+_ecore_evas_wl_common_free(Ecore_Evas *ee)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (ee->engine.wl.win) ecore_wl_window_free(ee->engine.wl.win);
+ ee->engine.wl.win = NULL;
+
+ ecore_event_window_unregister(ee->prop.window);
+ ecore_evas_input_event_unregister(ee);
+
+ _ecore_evas_wl_common_shutdown();
+ ecore_wl_shutdown();
+}
+
+void
+_ecore_evas_wl_common_resize(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->req.w = w;
+ ee->req.h = h;
+
+ if (!ee->prop.fullscreen)
+ {
+ int fw = 0, fh = 0;
+
+ if (ee->prop.min.w > w) w = ee->prop.min.w;
+ else if (w > ee->prop.max.w) w = ee->prop.max.w;
+ if (ee->prop.min.h > h) h = ee->prop.min.h;
+ else if (h > ee->prop.max.h) h = ee->prop.max.h;
+
+ evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
+ w += fw;
+ h += fh;
+ }
+
+ if ((ee->w != w) || (ee->h != h))
+ {
+ ee->w = w;
+ ee->h = h;
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, h, w);
+ evas_output_viewport_set(ee->evas, 0, 0, h, w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ }
+
+ if (ee->prop.avoid_damage)
+ {
+ int pdam = 0;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+
+ if (ee->engine.wl.frame)
+ evas_object_resize(ee->engine.wl.frame, w, h);
+ }
+}
+
+void
+_ecore_evas_wl_common_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_resize = func;
+}
+
+void
+_ecore_evas_wl_common_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_move = func;
+}
+
+void
+_ecore_evas_wl_common_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_delete_request = func;
+}
+
+void
+_ecore_evas_wl_common_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_focus_in = func;
+}
+
+void
+_ecore_evas_wl_common_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_focus_out = func;
+}
+
+void
+_ecore_evas_wl_common_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_mouse_in = func;
+}
+
+void
+_ecore_evas_wl_common_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee))
+{
+ if (!ee) return;
+ ee->func.fn_mouse_out = func;
+}
+
+void
+_ecore_evas_wl_common_move(Ecore_Evas *ee, int x, int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+
+ ee->req.x = x;
+ ee->req.y = y;
+
+ if ((ee->x != x) || (ee->y != y))
+ {
+ ee->x = x;
+ ee->y = y;
+ if (ee->engine.wl.win)
+ ecore_wl_window_update_location(ee->engine.wl.win, x, y);
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+}
+
+static void
+_ecore_evas_wl_common_smart_add(Evas_Object *obj)
+{
+ EE_Wl_Smart_Data *sd;
+ Evas *evas;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sd = calloc(1, sizeof(EE_Wl_Smart_Data)))) return;
+
+ evas = evas_object_evas_get(obj);
+
+ sd->x = 0;
+ sd->y = 0;
+ sd->w = 1;
+ sd->h = 1;
+
+ sd->frame = evas_object_rectangle_add(evas);
+ evas_object_color_set(sd->frame, 249, 249, 249, 255);
+ evas_object_smart_member_add(sd->frame, obj);
+
+ sd->text = evas_object_text_add(evas);
+ evas_object_color_set(sd->text, 0, 0, 0, 255);
+ evas_object_text_style_set(sd->text, EVAS_TEXT_STYLE_PLAIN);
+ evas_object_text_font_set(sd->text, "Sans", 10);
+ evas_object_text_text_set(sd->text, "Smart Test");
+ evas_object_smart_member_add(sd->text, obj);
+
+ evas_object_smart_data_set(obj, sd);
+}
+
+static void
+_ecore_evas_wl_common_smart_del(Evas_Object *obj)
+{
+ EE_Wl_Smart_Data *sd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sd = evas_object_smart_data_get(obj))) return;
+ evas_object_del(sd->text);
+ evas_object_del(sd->frame);
+ free(sd);
+}
+
+static void
+_ecore_evas_wl_common_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+ EE_Wl_Smart_Data *sd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sd = evas_object_smart_data_get(obj))) return;
+ if ((sd->w == w) && (sd->h == h)) return;
+ sd->w = w;
+ sd->h = h;
+ evas_object_resize(sd->frame, w, h);
+}
+
+static void
+_ecore_evas_wl_common_smart_show(Evas_Object *obj)
+{
+ EE_Wl_Smart_Data *sd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sd = evas_object_smart_data_get(obj))) return;
+ evas_object_show(sd->frame);
+ evas_object_show(sd->text);
+}
+
+static void
+_ecore_evas_wl_common_smart_hide(Evas_Object *obj)
+{
+ EE_Wl_Smart_Data *sd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sd = evas_object_smart_data_get(obj))) return;
+ evas_object_hide(sd->text);
+ evas_object_hide(sd->frame);
+}
+
+static void
+_ecore_evas_wl_common_smart_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (_ecore_evas_wl_common_smart) return;
+ {
+ static const Evas_Smart_Class sc =
+ {
+ "ecore_evas_wl_frame", EVAS_SMART_CLASS_VERSION,
+ _ecore_evas_wl_common_smart_add,
+ _ecore_evas_wl_common_smart_del,
+ NULL,
+ _ecore_evas_wl_common_smart_resize,
+ _ecore_evas_wl_common_smart_show,
+ _ecore_evas_wl_common_smart_hide,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+ _ecore_evas_wl_common_smart = evas_smart_class_new(&sc);
+ }
+}
+
+Evas_Object *
+_ecore_evas_wl_common_frame_add(Evas *evas)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_evas_wl_common_smart_init();
+ return evas_object_smart_add(evas, _ecore_evas_wl_common_smart);
+}
+
+void
+_ecore_evas_wl_common_raise(Ecore_Evas *ee)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!ee) || (!ee->visible)) return;
+ ecore_wl_window_raise(ee->engine.wl.win);
+}
+
+void
+_ecore_evas_wl_common_title_set(Ecore_Evas *ee, const char *title)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (title) ee->prop.title = strdup(title);
+ if ((ee->prop.draw_frame) && (ee->engine.wl.frame))
+ {
+ EE_Wl_Smart_Data *sd;
+
+ if ((sd = evas_object_smart_data_get(ee->engine.wl.frame)))
+ evas_object_text_text_set(sd->text, ee->prop.title);
+ }
+
+ if ((ee->prop.title) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_title(ee->engine.wl.win->shell_surface,
+ ee->prop.title);
+}
+
+void
+_ecore_evas_wl_common_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.name) free(ee->prop.name);
+ if (ee->prop.clas) free(ee->prop.clas);
+ ee->prop.name = NULL;
+ ee->prop.clas = NULL;
+ if (n) ee->prop.name = strdup(n);
+ if (c) ee->prop.clas = strdup(c);
+
+ if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_class(ee->engine.wl.win->shell_surface,
+ ee->prop.clas);
+}
+
+void
+_ecore_evas_wl_common_size_min_set(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return;
+ ee->prop.min.w = w;
+ ee->prop.min.h = h;
+}
+
+void
+_ecore_evas_wl_common_size_max_set(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return;
+ ee->prop.max.w = w;
+ ee->prop.max.h = h;
+}
+
+void
+_ecore_evas_wl_common_size_base_set(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return;
+ ee->prop.base.w = w;
+ ee->prop.base.h = h;
+}
+
+void
+_ecore_evas_wl_common_size_step_set(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return;
+ ee->prop.step.w = w;
+ ee->prop.step.h = h;
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee) ee->prop.cursor.object = NULL;
+}
+
+void
+_ecore_evas_wl_common_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y, fx, fy;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ ecore_wl_window_cursor_default_restore(ee->engine.wl.win);
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+
+ ecore_wl_window_pointer_set(ee->engine.wl.win, NULL, 0, 0);
+
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_output_framespace_get(ee->evas, &fx, &fy, NULL, NULL);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - fx - ee->prop.cursor.hot.x,
+ y - fy - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+void
+_ecore_evas_wl_common_layer_set(Ecore_Evas *ee, int layer)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.layer == layer) return;
+ if (layer < 1) layer = 1;
+ else if (layer > 255) layer = 255;
+ ee->prop.layer = layer;
+}
+
+void
+_ecore_evas_wl_common_iconified_set(Ecore_Evas *ee, int iconify)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.iconified == iconify) return;
+ ee->prop.iconified = iconify;
+ /* FIXME: Implement this in Wayland someshow */
+}
+
+void
+_ecore_evas_wl_common_maximized_set(Ecore_Evas *ee, int max)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.maximized == max) return;
+ ee->prop.maximized = max;
+ ecore_wl_window_maximized_set(ee->engine.wl.win, max);
+}
+
+void
+_ecore_evas_wl_common_fullscreen_set(Ecore_Evas *ee, int full)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->prop.fullscreen == full) return;
+ ee->prop.fullscreen = full;
+ ecore_wl_window_fullscreen_set(ee->engine.wl.win, full);
+}
+
+void
+_ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ ee->ignore_events = ignore;
+ /* NB: Hmmm, may need to pass this to ecore_wl_window in the future */
+}
+
+int
+_ecore_evas_wl_common_pre_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *ll = NULL;
+ Ecore_Evas *ee2 = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ return rend;
+}
+
+int
+_ecore_evas_wl_common_render_updates(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *updates = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((updates = evas_render_updates(ee->evas)))
+ {
+ Eina_List *l = NULL;
+ Eina_Rectangle *r;
+
+ EINA_LIST_FOREACH(updates, l, r)
+ ecore_wl_window_damage(ee->engine.wl.win,
+ r->x, r->y, r->w, r->h);
+
+ ecore_wl_flush();
+
+ evas_render_updates_free(updates);
+ rend = 1;
+ }
+
+ return rend;
+}
+
+void
+_ecore_evas_wl_common_post_render(Ecore_Evas *ee)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_evas_idle_timeout_update(ee);
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+}
+
+int
+_ecore_evas_wl_common_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return 0;
+ if (!ee->visible)
+ {
+ evas_norender(ee->evas);
+ return 0;
+ }
+
+ rend = _ecore_evas_wl_common_pre_render(ee);
+ rend |= _ecore_evas_wl_common_render_updates(ee);
+ _ecore_evas_wl_common_post_render(ee);
+
+ return rend;
+}
+
+void
+_ecore_evas_wl_common_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ ecore_wl_screen_size_get(w, h);
+}
+
+void
+_ecore_evas_wl_common_screen_dpi_get(const Ecore_Evas *ee EINA_UNUSED, int *xdpi, int *ydpi)
+{
+ int dpi = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (xdpi) *xdpi = 0;
+ if (ydpi) *ydpi = 0;
+ /* FIXME: Ideally this needs to get the DPI from a specific screen */
+ dpi = ecore_wl_dpi_get();
+ if (xdpi) *xdpi = dpi;
+ if (ydpi) *ydpi = dpi;
+}
diff --git a/src/lib/ecore_evas/ecore_evas_wayland_egl.c b/src/lib/ecore_evas/ecore_evas_wayland_egl.c
new file mode 100644
index 0000000000..ed176e8b6e
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_wayland_egl.c
@@ -0,0 +1,434 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+//#define LOGFNS 1
+
+#ifdef LOGFNS
+# include <stdio.h>
+# define LOGFN(fl, ln, fn) \
+ printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn);
+#else
+# define LOGFN(fl, ln, fn)
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+# include <stdlib.h>
+# include <string.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/mman.h>
+#endif
+
+#include <Eina.h>
+
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL
+# include "ecore_evas_private.h"
+# include <Evas_Engine_Wayland_Egl.h>
+# include <Ecore_Wayland.h>
+
+/* local function prototypes */
+static void _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h);
+static void _ecore_evas_wl_show(Ecore_Evas *ee);
+static void _ecore_evas_wl_hide(Ecore_Evas *ee);
+static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha);
+static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent);
+
+static Ecore_Evas_Engine_Func _ecore_wl_engine_func =
+{
+ _ecore_evas_wl_common_free,
+ _ecore_evas_wl_common_callback_resize_set,
+ _ecore_evas_wl_common_callback_move_set,
+ NULL,
+ NULL,
+ _ecore_evas_wl_common_callback_delete_request_set,
+ NULL,
+ _ecore_evas_wl_common_callback_focus_in_set,
+ _ecore_evas_wl_common_callback_focus_out_set,
+ _ecore_evas_wl_common_callback_mouse_in_set,
+ _ecore_evas_wl_common_callback_mouse_out_set,
+ NULL, // sticky_set
+ NULL, // unsticky_set
+ NULL, // pre_render_set
+ NULL, // post_render_set
+ _ecore_evas_wl_common_move,
+ NULL, // managed_move
+ _ecore_evas_wl_resize,
+ NULL, // move_resize
+ NULL, // rotation_set
+ NULL, // shaped_set
+ _ecore_evas_wl_show,
+ _ecore_evas_wl_hide,
+ _ecore_evas_wl_common_raise,
+ NULL, // lower
+ NULL, // activate
+ _ecore_evas_wl_common_title_set,
+ _ecore_evas_wl_common_name_class_set,
+ _ecore_evas_wl_common_size_min_set,
+ _ecore_evas_wl_common_size_max_set,
+ _ecore_evas_wl_common_size_base_set,
+ _ecore_evas_wl_common_size_step_set,
+ _ecore_evas_wl_common_object_cursor_set,
+ _ecore_evas_wl_common_layer_set,
+ NULL, // focus set
+ _ecore_evas_wl_common_iconified_set,
+ NULL, // borderless set
+ NULL, // override set
+ _ecore_evas_wl_common_maximized_set,
+ _ecore_evas_wl_common_fullscreen_set,
+ NULL, // func avoid_damage set
+ NULL, // func withdrawn set
+ NULL, // func sticky set
+ _ecore_evas_wl_common_ignore_events_set,
+ _ecore_evas_wl_alpha_set,
+ _ecore_evas_wl_transparent_set,
+ NULL, // func profiles set
+ NULL, // window group set
+ NULL, // aspect set
+ NULL, // urgent set
+ NULL, // modal set
+ NULL, // demand attention set
+ NULL, // focus skip set
+ _ecore_evas_wl_common_render,
+ _ecore_evas_wl_common_screen_geometry_get,
+ _ecore_evas_wl_common_screen_dpi_get
+};
+
+/* external variables */
+
+/* external functions */
+EAPI Ecore_Evas *
+ecore_evas_wayland_egl_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame)
+{
+ Ecore_Wl_Window *p = NULL;
+ Evas_Engine_Info_Wayland_Egl *einfo;
+ Ecore_Evas *ee;
+ int method = 0, count = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(method = evas_render_method_lookup("wayland_egl")))
+ {
+ ERR("Render method lookup failed for Wayland_Egl");
+ return NULL;
+ }
+
+ count = ecore_wl_init(disp_name);
+ if (!count)
+ {
+ ERR("Failed to initialize Ecore_Wayland");
+ return NULL;
+ }
+ else if (count == 1)
+ ecore_wl_display_iterate();
+
+ if (!(ee = calloc(1, sizeof(Ecore_Evas))))
+ {
+ ERR("Failed to allocate Ecore_Evas");
+ goto ee_err;
+ }
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_wl_common_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wl_engine_func;
+
+ ee->driver = "wayland_egl";
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ ee->rotation = 0;
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->prop.draw_frame = frame;
+ ee->alpha = EINA_FALSE;
+
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, method);
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+
+ /* FIXME: This needs to be set based on theme & scale */
+ if (ee->prop.draw_frame)
+ evas_output_framespace_set(ee->evas, 4, 18, 8, 22);
+
+ if (parent)
+ p = ecore_wl_window_find(parent);
+
+ /* FIXME: Get if parent is alpha, and set */
+
+ ee->engine.wl.parent = p;
+ ee->engine.wl.win =
+ ecore_wl_window_new(p, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW);
+ ee->prop.window = ee->engine.wl.win->id;
+
+ if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.display = ecore_wl_display_get();
+ einfo->info.destination_alpha = ee->alpha;
+ einfo->info.rotation = ee->rotation;
+ einfo->info.depth = 32;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("Failed to set Evas Engine Info for '%s'", ee->driver);
+ goto err;
+ }
+ }
+ else
+ {
+ ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+ goto err;
+ }
+
+ ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_common_pre_free);
+
+ if (ee->prop.draw_frame)
+ {
+ ee->engine.wl.frame = _ecore_evas_wl_common_frame_add(ee->evas);
+ evas_object_is_frame_object_set(ee->engine.wl.frame, EINA_TRUE);
+ evas_object_move(ee->engine.wl.frame, 0, 0);
+ }
+
+ _ecore_evas_register(ee);
+ ecore_evas_input_event_register(ee);
+
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ return ee;
+
+ err:
+ ecore_evas_free(ee);
+ _ecore_evas_wl_common_shutdown();
+
+ ee_err:
+ ecore_wl_shutdown();
+ return NULL;
+}
+
+static void
+_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->req.w = w;
+ ee->req.h = h;
+
+ if (!ee->prop.fullscreen)
+ {
+ int fw = 0, fh = 0;
+
+ if (ee->prop.min.w > w) w = ee->prop.min.w;
+ else if (w > ee->prop.max.w) w = ee->prop.max.w;
+ if (ee->prop.min.h > h) h = ee->prop.min.h;
+ else if (h > ee->prop.max.h) h = ee->prop.max.h;
+
+ evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
+ w += fw;
+ h += fh;
+ }
+
+ if ((ee->w != w) || (ee->h != h))
+ {
+ ee->w = w;
+ ee->h = h;
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, h, w);
+ evas_output_viewport_set(ee->evas, 0, 0, h, w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ }
+
+ if (ee->prop.avoid_damage)
+ {
+ int pdam = 0;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+
+ if (ee->engine.wl.frame)
+ evas_object_resize(ee->engine.wl.frame, w, h);
+
+
+ if (ee->engine.wl.win)
+ {
+ ecore_wl_window_update_size(ee->engine.wl.win, w, h);
+ ecore_wl_window_buffer_attach(ee->engine.wl.win, NULL, 0, 0);
+ }
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+static void
+_ecore_evas_wl_show(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Wayland_Egl *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!ee) || (ee->visible)) return;
+
+ if (ee->engine.wl.win)
+ {
+ ecore_wl_window_show(ee->engine.wl.win);
+ ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h);
+ ecore_wl_window_buffer_attach(ee->engine.wl.win, NULL, 0, 0);
+
+ if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_class(ee->engine.wl.win->shell_surface,
+ ee->prop.clas);
+ if ((ee->prop.title) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_title(ee->engine.wl.win->shell_surface,
+ ee->prop.title);
+ }
+
+ if (ee->engine.wl.frame)
+ {
+ evas_object_show(ee->engine.wl.frame);
+ evas_object_resize(ee->engine.wl.frame, ee->w, ee->h);
+ }
+
+ if (ee->engine.wl.win)
+ {
+ einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas);
+ if (!einfo)
+ {
+ ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+ return;
+ }
+
+ einfo->info.surface = ecore_wl_window_surface_get(ee->engine.wl.win);
+ /* if (einfo->info.surface) */
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ /* else */
+ /* printf("Failed to get a Surface from Ecore_Wl\n"); */
+ }
+
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+}
+
+static void
+_ecore_evas_wl_hide(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Wayland_Egl *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!ee) || (!ee->visible)) return;
+
+ einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.surface = NULL;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ }
+
+ if (ee->engine.wl.win)
+ ecore_wl_window_hide(ee->engine.wl.win);
+
+ ee->visible = 0;
+ ee->should_be_visible = 0;
+
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+}
+
+static void
+_ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ Evas_Engine_Info_Wayland_Egl *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if ((ee->alpha == alpha)) return;
+ ee->alpha = alpha;
+ if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.destination_alpha = alpha;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+}
+
+static void
+_ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent)
+{
+ Evas_Engine_Info_Wayland_Egl *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if ((ee->transparent == transparent)) return;
+ ee->transparent = transparent;
+ if (!ee->visible) return;
+ if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.destination_alpha = transparent;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+}
+
+void
+_ecore_evas_wayland_egl_resize(Ecore_Evas *ee, int location)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->engine.wl.win)
+ {
+ Evas_Engine_Info_Wayland_Egl *einfo;
+
+ if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.edges = location;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+
+ ee->engine.wl.win->resizing = EINA_TRUE;
+ ecore_wl_window_resize(ee->engine.wl.win, ee->w, ee->h, location);
+ }
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_wayland_egl_new(const char *disp_name EINA_UNUSED, unsigned int parent EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, Eina_Bool frame EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_wayland_shm.c b/src/lib/ecore_evas/ecore_evas_wayland_shm.c
new file mode 100644
index 0000000000..24e349534a
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_wayland_shm.c
@@ -0,0 +1,656 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+//#define LOGFNS 1
+
+#ifdef LOGFNS
+# include <stdio.h>
+# define LOGFN(fl, ln, fn) \
+ printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn);
+#else
+# define LOGFN(fl, ln, fn)
+#endif
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+# include <stdlib.h>
+# include <string.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/mman.h>
+#endif
+
+#include <Eina.h>
+
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM
+# include "ecore_evas_private.h"
+# include <Evas_Engine_Wayland_Shm.h>
+# include <Ecore_Wayland.h>
+
+/* local function prototypes */
+static void _ecore_evas_wl_free(Ecore_Evas *ee);
+static void _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h);
+static void _ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h);
+static void _ecore_evas_wl_show(Ecore_Evas *ee);
+static void _ecore_evas_wl_hide(Ecore_Evas *ee);
+static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha);
+static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent);
+static int _ecore_evas_wl_render(Ecore_Evas *ee);
+
+/* SHM Only */
+static void _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee);
+static void _ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size);
+static void _ecore_evas_wl_buffer_free(Ecore_Evas *ee);
+static void _ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h);
+
+/* Frame listener */
+static void _ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time);
+static const struct wl_callback_listener frame_listener =
+{
+ _ecore_evas_wl_frame_complete,
+};
+
+static Ecore_Evas_Engine_Func _ecore_wl_engine_func =
+{
+ _ecore_evas_wl_free,
+ _ecore_evas_wl_common_callback_resize_set,
+ _ecore_evas_wl_common_callback_move_set,
+ NULL,
+ NULL,
+ _ecore_evas_wl_common_callback_delete_request_set,
+ NULL,
+ _ecore_evas_wl_common_callback_focus_in_set,
+ _ecore_evas_wl_common_callback_focus_out_set,
+ _ecore_evas_wl_common_callback_mouse_in_set,
+ _ecore_evas_wl_common_callback_mouse_out_set,
+ NULL, // sticky_set
+ NULL, // unsticky_set
+ NULL, // pre_render_set
+ NULL, // post_render_set
+ _ecore_evas_wl_common_move,
+ NULL, // managed_move
+ _ecore_evas_wl_resize,
+ _ecore_evas_wl_move_resize,
+ NULL, // rotation_set
+ NULL, // shaped_set
+ _ecore_evas_wl_show,
+ _ecore_evas_wl_hide,
+ _ecore_evas_wl_common_raise,
+ NULL, // lower
+ NULL, // activate
+ _ecore_evas_wl_common_title_set,
+ _ecore_evas_wl_common_name_class_set,
+ _ecore_evas_wl_common_size_min_set,
+ _ecore_evas_wl_common_size_max_set,
+ _ecore_evas_wl_common_size_base_set,
+ _ecore_evas_wl_common_size_step_set,
+ _ecore_evas_wl_common_object_cursor_set,
+ _ecore_evas_wl_common_layer_set,
+ NULL, // focus set
+ _ecore_evas_wl_common_iconified_set,
+ NULL, // borderless set
+ NULL, // override set
+ _ecore_evas_wl_common_maximized_set,
+ _ecore_evas_wl_common_fullscreen_set,
+ NULL, // func avoid_damage set
+ NULL, // func withdrawn set
+ NULL, // func sticky set
+ _ecore_evas_wl_common_ignore_events_set,
+ _ecore_evas_wl_alpha_set,
+ _ecore_evas_wl_transparent_set,
+ NULL, // func profiles set
+ NULL, // window group set
+ NULL, // aspect set
+ NULL, // urgent set
+ NULL, // modal set
+ NULL, // demand attention set
+ NULL, // focus skip set
+ _ecore_evas_wl_render,
+ _ecore_evas_wl_common_screen_geometry_get,
+ _ecore_evas_wl_common_screen_dpi_get
+};
+
+/* external variables */
+
+/* external functions */
+EAPI Ecore_Evas *
+ecore_evas_wayland_shm_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame)
+{
+ Ecore_Wl_Window *p = NULL;
+ Evas_Engine_Info_Wayland_Shm *einfo;
+ Ecore_Evas *ee;
+ int method = 0, count = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(method = evas_render_method_lookup("wayland_shm")))
+ {
+ ERR("Render method lookup failed for Wayland_Shm");
+ return NULL;
+ }
+
+ count = ecore_wl_init(disp_name);
+ if (!count)
+ {
+ ERR("Failed to initialize Ecore_Wayland");
+ return NULL;
+ }
+ else if (count == 1)
+ ecore_wl_display_iterate();
+
+ if (!(ee = calloc(1, sizeof(Ecore_Evas))))
+ {
+ ERR("Failed to allocate Ecore_Evas");
+ goto ee_err;
+ }
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_wl_common_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wl_engine_func;
+
+ ee->driver = "wayland_shm";
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ ee->rotation = 0;
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->prop.draw_frame = frame;
+ ee->alpha = EINA_FALSE;
+
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, method);
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+
+ /* FIXME: This needs to be set based on theme & scale */
+ if (ee->prop.draw_frame)
+ evas_output_framespace_set(ee->evas, 4, 18, 8, 22);
+
+ if (parent)
+ p = ecore_wl_window_find(parent);
+
+ /* FIXME: Get if parent is alpha, and set */
+
+ ee->engine.wl.parent = p;
+ ee->engine.wl.win =
+ ecore_wl_window_new(p, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_SHM);
+ ee->prop.window = ee->engine.wl.win->id;
+
+ if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.destination_alpha = ee->alpha;
+ einfo->info.rotation = ee->rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("Failed to set Evas Engine Info for '%s'", ee->driver);
+ goto err;
+ }
+ }
+ else
+ {
+ ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+ goto err;
+ }
+
+ ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_common_pre_free);
+
+ if (ee->prop.draw_frame)
+ {
+ ee->engine.wl.frame = _ecore_evas_wl_common_frame_add(ee->evas);
+ evas_object_is_frame_object_set(ee->engine.wl.frame, EINA_TRUE);
+ evas_object_move(ee->engine.wl.frame, 0, 0);
+ }
+
+ _ecore_evas_register(ee);
+ ecore_evas_input_event_register(ee);
+
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ return ee;
+
+ err:
+ ecore_evas_free(ee);
+ _ecore_evas_wl_common_shutdown();
+
+ ee_err:
+ ecore_wl_shutdown();
+ return NULL;
+}
+
+static void
+_ecore_evas_wl_free(Ecore_Evas *ee)
+{
+ _ecore_evas_wl_buffer_free(ee);
+ _ecore_evas_wl_shm_pool_free(ee);
+ _ecore_evas_wl_common_free(ee);
+}
+
+static void
+_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h)
+{
+ Evas_Engine_Info_Wayland_Shm *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ ee->req.w = w;
+ ee->req.h = h;
+
+ if (!ee->prop.fullscreen)
+ {
+ int fw = 0, fh = 0;
+
+ if (ee->prop.min.w > w) w = ee->prop.min.w;
+ else if (w > ee->prop.max.w) w = ee->prop.max.w;
+ if (ee->prop.min.h > h) h = ee->prop.min.h;
+ else if (h > ee->prop.max.h) h = ee->prop.max.h;
+
+ evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
+ w += fw;
+ h += fh;
+ }
+
+ if ((ee->w != w) || (ee->h != h))
+ {
+ ee->w = w;
+ ee->h = h;
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, h, w);
+ evas_output_viewport_set(ee->evas, 0, 0, h, w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+ }
+
+ if (ee->prop.avoid_damage)
+ {
+ int pdam = 0;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+
+ if (ee->engine.wl.frame)
+ evas_object_resize(ee->engine.wl.frame, w, h);
+
+ _ecore_evas_wl_buffer_new(ee, w, h);
+
+ einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
+ if (!einfo)
+ {
+ ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+ return;
+ }
+
+ einfo->info.dest = ee->engine.wl.pool_data;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+
+ if (ee->engine.wl.win)
+ {
+ ecore_wl_window_update_size(ee->engine.wl.win, w, h);
+ ecore_wl_window_buffer_attach(ee->engine.wl.win,
+ ee->engine.wl.buffer, 0, 0);
+ }
+
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+static void
+_ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if ((ee->x != x) || (ee->y != y))
+ _ecore_evas_wl_common_move(ee, x, y);
+ if ((ee->w != w) || (ee->h != h))
+ _ecore_evas_wl_resize(ee, w, h);
+}
+
+static void
+_ecore_evas_wl_show(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Wayland_Shm *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!ee) || (ee->visible)) return;
+
+ _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
+
+ einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
+ if (!einfo)
+ {
+ ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+ return;
+ }
+
+ einfo->info.dest = ee->engine.wl.pool_data;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+
+ if (ee->engine.wl.win)
+ {
+ ecore_wl_window_show(ee->engine.wl.win);
+ ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h);
+ ecore_wl_window_buffer_attach(ee->engine.wl.win,
+ ee->engine.wl.buffer, 0, 0);
+
+ if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_class(ee->engine.wl.win->shell_surface,
+ ee->prop.clas);
+ if ((ee->prop.title) && (ee->engine.wl.win->shell_surface))
+ wl_shell_surface_set_title(ee->engine.wl.win->shell_surface,
+ ee->prop.title);
+ }
+
+ if (ee->engine.wl.frame)
+ {
+ evas_object_show(ee->engine.wl.frame);
+ evas_object_resize(ee->engine.wl.frame, ee->w, ee->h);
+ }
+
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+}
+
+static void
+_ecore_evas_wl_hide(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Wayland_Shm *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!ee) || (!ee->visible)) return;
+
+ _ecore_evas_wl_buffer_free(ee);
+
+ munmap(ee->engine.wl.pool_data, ee->engine.wl.pool_size);
+
+ einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas);
+ if ((einfo) && (einfo->info.dest))
+ {
+ einfo->info.dest = NULL;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ }
+
+ if (ee->engine.wl.win)
+ ecore_wl_window_hide(ee->engine.wl.win);
+
+ ee->visible = 0;
+ ee->should_be_visible = 0;
+
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+}
+
+static void
+_ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ Evas_Engine_Info_Wayland_Shm *einfo;
+ Ecore_Wl_Window *win = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if ((ee->alpha == alpha)) return;
+ ee->alpha = alpha;
+
+ /* FIXME: NB: We should really add a ecore_wl_window_alpha_set function
+ * but we are in API freeze, so just hack it in for now and fix when
+ * freeze is over */
+ if ((win = ee->engine.wl.win))
+ win->alpha = alpha;
+
+ /* if (ee->engine.wl.win) */
+ /* ecore_wl_window_transparent_set(ee->engine.wl.win, alpha); */
+
+ _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
+
+ if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.destination_alpha = alpha;
+ einfo->info.dest = ee->engine.wl.pool_data;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+
+ if (win)
+ {
+ ecore_wl_window_update_size(win, ee->w, ee->h);
+ ecore_wl_window_buffer_attach(win, ee->engine.wl.buffer, 0, 0);
+ }
+}
+
+static void
+_ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent)
+{
+ Evas_Engine_Info_Wayland_Shm *einfo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if ((ee->transparent == transparent)) return;
+ ee->transparent = transparent;
+
+ if (ee->engine.wl.win)
+ ecore_wl_window_transparent_set(ee->engine.wl.win, transparent);
+
+ _ecore_evas_wl_buffer_new(ee, ee->w, ee->h);
+
+ if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas)))
+ {
+ einfo->info.destination_alpha = transparent;
+ einfo->info.dest = ee->engine.wl.pool_data;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+
+ if (ee->engine.wl.win)
+ {
+ ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h);
+ ecore_wl_window_buffer_attach(ee->engine.wl.win,
+ ee->engine.wl.buffer, 0, 0);
+ }
+}
+
+static void
+_ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+ Ecore_Wl_Window *win = NULL;
+
+ if (!ee) return;
+ if (!(win = ee->engine.wl.win)) return;
+
+ win->frame_callback = NULL;
+ win->frame_pending = EINA_FALSE;
+ wl_callback_destroy(callback);
+
+ if (win->surface)
+ {
+ win->frame_callback = wl_surface_frame(win->surface);
+ wl_callback_add_listener(win->frame_callback, &frame_listener, ee);
+ }
+}
+
+static int
+_ecore_evas_wl_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Ecore_Wl_Window *win = NULL;
+
+ if (!ee) return 0;
+ if (!ee->visible)
+ {
+ evas_norender(ee->evas);
+ return 0;
+ }
+
+ if (!(win = ee->engine.wl.win)) return 0;
+
+ rend = _ecore_evas_wl_common_pre_render(ee);
+ if (!(win->frame_pending))
+ {
+ /* FIXME - ideally have an evas_changed_get to return the value
+ * of evas->changed to avoid creating this callback and
+ * destroying it again
+ */
+
+ if (!win->frame_callback)
+ {
+ win->frame_callback = wl_surface_frame(win->surface);
+ wl_callback_add_listener(win->frame_callback, &frame_listener, ee);
+ }
+
+ rend |= _ecore_evas_wl_common_render_updates(ee);
+ if (rend)
+ win->frame_pending = EINA_TRUE;
+ }
+ _ecore_evas_wl_common_post_render(ee);
+ return rend;
+}
+
+static void
+_ecore_evas_wl_shm_pool_free(Ecore_Evas *ee)
+{
+ if (!ee->engine.wl.pool) return;
+
+ wl_shm_pool_destroy(ee->engine.wl.pool);
+ ee->engine.wl.pool = NULL;
+ ee->engine.wl.pool_size = 0;
+ ee->engine.wl.pool_data = NULL;
+}
+
+static void
+_ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size)
+{
+ struct wl_shm *shm;
+ void *data;
+ char tmp[PATH_MAX];
+ int fd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (size <= ee->engine.wl.pool_size)
+ return;
+
+ size *= 1.5;
+ _ecore_evas_wl_shm_pool_free(ee);
+
+ if (!(shm = ecore_wl_shm_get()))
+ {
+ ERR("ecore_wl_shm_get returned NULL");
+ return;
+ }
+
+ strcpy(tmp, "/tmp/ecore-evas-wayland_shm-XXXXXX");
+ if ((fd = mkstemp(tmp)) < 0)
+ {
+ ERR("Could not create temporary file.");
+ return;
+ }
+
+ if (ftruncate(fd, size) < 0)
+ {
+ ERR("Could not truncate temporary file.");
+ goto end;
+ }
+
+ data = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
+ unlink(tmp);
+
+ if (data == MAP_FAILED)
+ {
+ ERR("mmap of temporary file failed.");
+ goto end;
+ }
+
+ ee->engine.wl.pool_size = size;
+ ee->engine.wl.pool_data = data;
+ ee->engine.wl.pool = wl_shm_create_pool(shm, fd, size);
+
+ end:
+ close(fd);
+}
+
+static void
+_ecore_evas_wl_buffer_free(Ecore_Evas *ee)
+{
+ if (!ee->engine.wl.buffer) return;
+
+ wl_buffer_destroy(ee->engine.wl.buffer);
+ ee->engine.wl.buffer = NULL;
+}
+
+static void
+_ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h)
+{
+ unsigned int format;
+ int stride = 0;
+
+ stride = (w * sizeof(int));
+
+ _ecore_evas_wl_shm_pool_create(ee, stride * h);
+
+ if ((ee->alpha) || (ee->transparent))
+ format = WL_SHM_FORMAT_ARGB8888;
+ else
+ format = WL_SHM_FORMAT_XRGB8888;
+
+ _ecore_evas_wl_buffer_free(ee);
+ ee->engine.wl.buffer =
+ wl_shm_pool_create_buffer(ee->engine.wl.pool, 0, w, h, stride, format);
+}
+
+void
+_ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ee) return;
+ if (ee->engine.wl.win)
+ {
+ ee->engine.wl.win->resizing = EINA_TRUE;
+ ecore_wl_window_resize(ee->engine.wl.win, ee->w, ee->h, location);
+ }
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_wayland_shm_new(const char *disp_name EINA_UNUSED, unsigned int parent EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, Eina_Bool frame EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
diff --git a/src/lib/ecore_evas/ecore_evas_win32.c b/src/lib/ecore_evas/ecore_evas_win32.c
new file mode 100644
index 0000000000..32ecc46de4
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_win32.c
@@ -0,0 +1,1524 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h> /* for NULL */
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#ifdef BUILD_ECORE_EVAS_WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# include <Ecore_Win32.h>
+# include <ecore_win32_private.h>
+#endif /* BUILD_ECORE_EVAS_WIN32 */
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_WIN32
+
+#define ECORE_EVAS_EVENT_COUNT 10
+
+static int _ecore_evas_init_count = 0;
+
+static Ecore_Event_Handler *ecore_evas_event_handlers[ECORE_EVAS_EVENT_COUNT];
+
+static Eina_Bool _ecore_evas_win32_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_damage(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_hide(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_configure(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+static Eina_Bool _ecore_evas_win32_event_window_delete_request(void *data EINA_UNUSED, int type EINA_UNUSED, void *event);
+
+/* Private functions */
+
+static int
+_ecore_evas_win32_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *updates = NULL;
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+ if (ee->prop.avoid_damage)
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ else if ((ee->visible) ||
+ ((ee->should_be_visible) && (ee->prop.fullscreen)) ||
+ ((ee->should_be_visible) && (ee->prop.override)))
+ {
+ if (ee->shaped)
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ else
+ {
+ updates = evas_render_updates(ee->evas);
+ if (updates) evas_render_updates_free(updates);
+ }
+ }
+ else
+ evas_norender(ee->evas);
+ if (updates) rend = 1;
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ return rend;
+}
+
+static int
+_ecore_evas_win32_init(void)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1)
+ return _ecore_evas_init_count;
+
+ ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_IN, _ecore_evas_win32_event_mouse_in, NULL);
+ ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_OUT, _ecore_evas_win32_event_mouse_out, NULL);
+ ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_IN, _ecore_evas_win32_event_window_focus_in, NULL);
+ ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT, _ecore_evas_win32_event_window_focus_out, NULL);
+ ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, _ecore_evas_win32_event_window_damage, NULL);
+ ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DESTROY, _ecore_evas_win32_event_window_destroy, NULL);
+ ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_SHOW, _ecore_evas_win32_event_window_show, NULL);
+ ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_HIDE, _ecore_evas_win32_event_window_hide, NULL);
+ ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, _ecore_evas_win32_event_window_configure, NULL);
+ ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_win32_event_window_delete_request, NULL);
+
+ ecore_event_evas_init();
+ return _ecore_evas_init_count;
+}
+
+int
+_ecore_evas_win32_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ int i;
+
+ for (i = 0; i < ECORE_EVAS_EVENT_COUNT; i++)
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ ecore_event_evas_shutdown();
+ }
+
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+
+ return _ecore_evas_init_count;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Mouse_In *e;
+
+ INF("mouse in");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+
+ if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee);
+ /* FIXME to do */
+/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */
+ evas_event_feed_mouse_in(ee->evas, e->timestamp, NULL);
+ evas_focus_in(ee->evas);
+ _ecore_evas_mouse_move_process(ee, e->x, e->y, e->timestamp);
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Mouse_Out *e;
+
+ INF("mouse out");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+
+ /* FIXME to do */
+/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */
+ _ecore_evas_mouse_move_process(ee, e->x, e->y, e->timestamp);
+
+ evas_event_feed_mouse_out(ee->evas, e->timestamp, NULL);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Focus_In *e;
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if ((Ecore_Window)e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Focus_Out *e;
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ if ((Ecore_Window)e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+
+ evas_focus_out(ee->evas);
+ ee->prop.focused = 0;
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_damage(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Damage *e;
+
+ INF("window damage");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+
+ if (ee->prop.avoid_damage)
+ {
+#ifdef _MSC_VER
+# pragma message ("[ECORE] [WIN32] No Region code")
+#else
+# warning [ECORE] [WIN32] No Region code
+#endif /* ! _MSC_VER */
+ }
+ else
+ {
+ if (ee->rotation == 0)
+ evas_damage_rectangle_add(ee->evas,
+ e->x,
+ e->y,
+ e->width,
+ e->height);
+ else if (ee->rotation == 90)
+ evas_damage_rectangle_add(ee->evas,
+ ee->h - e->y - e->height,
+ e->x,
+ e->height,
+ e->width);
+ else if (ee->rotation == 180)
+ evas_damage_rectangle_add(ee->evas,
+ ee->w - e->x - e->width,
+ ee->h - e->y - e->height,
+ e->width,
+ e->height);
+ else if (ee->rotation == 270)
+ evas_damage_rectangle_add(ee->evas,
+ e->y,
+ ee->w - e->x - e->width,
+ e->height,
+ e->width);
+ }
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Destroy *e;
+
+ INF("window destroy");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+ if (ee->func.fn_destroy) ee->func.fn_destroy(ee);
+ ecore_evas_free(ee);
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Show *e;
+
+ INF("window show");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+ if (ee->visible) return 0; /* dont pass it on */
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_hide(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Hide *e;
+
+ INF("window hide");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+ if (!ee->visible) return 0; /* dont pass it on */
+ ee->visible = 0;
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_configure(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Configure *e;
+
+ INF("window configure");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+
+ if (ee->prop.override)
+ {
+ if ((ee->x != e->x) || (ee->y != e->y))
+ {
+ ee->x = e->x;
+ ee->y = e->y;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ }
+
+ if ((ee->w != e->width) || (ee->h != e->height))
+ {
+ ee->w = e->width;
+ ee->h = e->height;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+/* if (ee->shaped) */
+/* _ecore_evas_win32_region_border_resize(ee); */
+ if ((ee->expecting_resize.w > 0) &&
+ (ee->expecting_resize.h > 0))
+ {
+ if ((ee->expecting_resize.w == ee->w) &&
+ (ee->expecting_resize.h == ee->h))
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_win32_current_time_get());
+ ee->expecting_resize.w = 0;
+ ee->expecting_resize.h = 0;
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+
+ return 1;
+}
+
+static Eina_Bool
+_ecore_evas_win32_event_window_delete_request(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_Win32_Event_Window_Delete_Request *e;
+
+ INF("window delete request");
+
+ e = event;
+ ee = ecore_event_window_match((Ecore_Window)e->window);
+ if (!ee) return 1; /* pass on event */
+ if ((Ecore_Window)e->window != ee->prop.window) return 1;
+ if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee);
+
+ INF(" * ee event delete\n");
+ return 1;
+}
+
+
+/* Ecore_Evas interface */
+
+static void
+_ecore_evas_win32_free(Ecore_Evas *ee)
+{
+ INF("ecore evas free");
+
+ ecore_win32_window_free((struct _Ecore_Win32_Window *)ee->prop.window);
+ ecore_event_window_unregister(ee->prop.window);
+ _ecore_evas_win32_shutdown();
+ ecore_win32_shutdown();
+}
+
+static void
+_ecore_evas_win32_callback_delete_request_set(Ecore_Evas *ee,
+ Ecore_Evas_Event_Cb func)
+{
+ ee->func.fn_delete_request = func;
+}
+
+static void
+_ecore_evas_win32_move(Ecore_Evas *ee, int x, int y)
+{
+ INF("ecore evas move (%dx%d)", x, y);
+ ee->req.x = x;
+ ee->req.y = y;
+
+ if ((x != ee->x) || (y != ee->y))
+ {
+ ee->x = x;
+ ee->y = y;
+ ecore_win32_window_move((struct _Ecore_Win32_Window *)ee->prop.window,
+ x, y);
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+}
+
+static void
+_ecore_evas_win32_resize(Ecore_Evas *ee, int width, int height)
+{
+ INF("ecore evas resize (%dx%d)", width, height);
+ ee->req.w = width;
+ ee->req.h = height;
+
+ if ((ee->w != width) || (ee->h != height))
+ {
+ ee->w = width;
+ ee->h = height;
+ ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window,
+ width, height);
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+/* if ((ee->shaped) || (ee->alpha)) */
+/* _ecore_evas_win32_region_border_resize(ee); */
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+}
+
+static void
+_ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int height)
+{
+ INF("ecore evas resize (%dx%d %dx%d)", x, y, width, height);
+ ee->req.x = x;
+ ee->req.y = y;
+ ee->req.w = width;
+ ee->req.h = height;
+
+ if ((ee->w != width) || (ee->h != height) || (x != ee->x) || (y != ee->y))
+ {
+ int change_size = 0;
+ int change_pos = 0;
+
+ if ((ee->w != width) || (ee->h != height)) change_size = 1;
+ if ((x != ee->x) || (y != ee->y)) change_pos = 1;
+
+ ee->x = x;
+ ee->y = y;
+ ee->w = width;
+ ee->h = height;
+ ecore_win32_window_move_resize((struct _Ecore_Win32_Window *)ee->prop.window,
+ x, y, width, height);
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+/* if ((ee->shaped) || (ee->alpha)) */
+/* _ecore_evas_win32_region_border_resize(ee); */
+ if (change_pos)
+ {
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ if (change_size)
+ {
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ }
+}
+
+static void
+_ecore_evas_win32_rotation_set_internal(Ecore_Evas *ee, int rotation)
+{
+ int rot_dif;
+
+ rot_dif = ee->rotation - rotation;
+ if (rot_dif < 0) rot_dif = -rot_dif;
+
+ if (rot_dif != 180)
+ {
+ int minw, minh, maxw, maxh, basew, baseh, stepw, steph;
+
+ if (!ee->prop.fullscreen)
+ {
+ ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window,
+ ee->h, ee->w);
+ ee->expecting_resize.w = ee->h;
+ ee->expecting_resize.h = ee->w;
+ }
+ else
+ {
+ int w, h;
+
+ ecore_win32_window_size_get((struct _Ecore_Win32_Window *)ee->prop.window,
+ &w, &h);
+ ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window,
+ h, w);
+ if ((rotation == 0) || (rotation == 180))
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ ecore_evas_size_min_get(ee, &minw, &minh);
+ ecore_evas_size_max_get(ee, &maxw, &maxh);
+ ecore_evas_size_base_get(ee, &basew, &baseh);
+ ecore_evas_size_step_get(ee, &stepw, &steph);
+ ee->rotation = rotation;
+ ecore_evas_size_min_set(ee, minh, minw);
+ ecore_evas_size_max_set(ee, maxh, maxw);
+ ecore_evas_size_base_set(ee, baseh, basew);
+ ecore_evas_size_step_set(ee, steph, stepw);
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_win32_current_time_get());
+ }
+ else
+ {
+ ee->rotation = rotation;
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_win32_current_time_get());
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+}
+
+static void
+_ecore_evas_win32_rotation_set(Ecore_Evas *ee, int rotation, int resize)
+{
+ INF("ecore evas rotation: %s", rotation ? "yes" : "no");
+
+ if (ee->rotation == rotation) return;
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ if (!strcmp(ee->driver, "software_gdi"))
+ {
+ Evas_Engine_Info_Software_Gdi *einfo;
+
+ einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+ einfo->info.rotation = rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ _ecore_evas_win32_rotation_set_internal(ee, rotation);
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+ if (!strcmp(ee->driver, "software_ddraw"))
+ {
+ Evas_Engine_Info_Software_DDraw *einfo;
+
+ einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+ einfo->info.rotation = rotation;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ _ecore_evas_win32_rotation_set_internal(ee, rotation);
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */
+}
+
+static void
+_ecore_evas_win32_shaped_set(Ecore_Evas *ee, int shaped)
+{
+ if (((ee->shaped) && (shaped)) || ((!ee->shaped) && (!shaped)))
+ return;
+
+ if (!strcmp(ee->driver, "software_ddraw")) return;
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ if (!strcmp(ee->driver, "software_gdi"))
+ {
+ Evas_Engine_Info_Software_Gdi *einfo;
+
+ einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas);
+ ee->shaped = shaped;
+ if (einfo)
+ {
+ ee->engine.win32.state.region = ee->shaped;
+ einfo->info.region = ee->engine.win32.state.region;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ if (ee->shaped)
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */
+ }
+}
+
+static void
+_ecore_evas_win32_show(Ecore_Evas *ee)
+{
+ INF("ecore evas show");
+
+ ee->should_be_visible = 1;
+ if (ee->prop.avoid_damage)
+ _ecore_evas_win32_render(ee);
+ ecore_win32_window_show((struct _Ecore_Win32_Window *)ee->prop.window);
+/* if (ee->prop.fullscreen) */
+/* ecore_win32_window_focus(ee->prop.window); */
+}
+
+static void
+_ecore_evas_win32_hide(Ecore_Evas *ee)
+{
+ INF("ecore evas hide");
+
+ ecore_win32_window_hide((struct _Ecore_Win32_Window *)ee->prop.window);
+ ee->should_be_visible = 0;
+}
+
+static void
+_ecore_evas_win32_raise(Ecore_Evas *ee)
+{
+ INF("ecore evas raise");
+
+ if (!ee->prop.fullscreen)
+ ecore_win32_window_raise((struct _Ecore_Win32_Window *)ee->prop.window);
+ else
+ ecore_win32_window_raise((struct _Ecore_Win32_Window *)ee->prop.window);
+}
+
+static void
+_ecore_evas_win32_lower(Ecore_Evas *ee)
+{
+ INF("ecore evas lower");
+
+ if (!ee->prop.fullscreen)
+ ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window);
+ else
+ ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window);
+}
+
+static void
+_ecore_evas_win32_activate(Ecore_Evas *ee)
+{
+ INF("ecore evas activate");
+
+ ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window);
+}
+
+static void
+_ecore_evas_win32_title_set(Ecore_Evas *ee, const char *title)
+{
+ INF("ecore evas title set");
+
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (title) ee->prop.title = strdup(title);
+ ecore_win32_window_title_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ ee->prop.title);
+}
+
+static void
+_ecore_evas_win32_size_min_set(Ecore_Evas *ee, int width, int height)
+{
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ if ((ee->prop.min.w == width) && (ee->prop.min.h == height)) return;
+ ee->prop.min.w = width;
+ ee->prop.min.h = height;
+ ecore_win32_window_size_min_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ width, height);
+}
+
+static void
+_ecore_evas_win32_size_max_set(Ecore_Evas *ee, int width, int height)
+{
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ if ((ee->prop.max.w == width) && (ee->prop.max.h == height)) return;
+ ee->prop.max.w = width;
+ ee->prop.max.h = height;
+ ecore_win32_window_size_max_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ width, height);
+}
+
+static void
+_ecore_evas_win32_size_base_set(Ecore_Evas *ee, int width, int height)
+{
+ if (width < 0) width = 0;
+ if (height < 0) height = 0;
+ if ((ee->prop.base.w == width) && (ee->prop.base.h == height)) return;
+ ee->prop.base.w = width;
+ ee->prop.base.h = height;
+ ecore_win32_window_size_base_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ width, height);
+}
+
+static void
+_ecore_evas_win32_size_step_set(Ecore_Evas *ee, int width, int height)
+{
+ if (width < 1) width = 1;
+ if (height < 1) height = 1;
+ if ((ee->prop.step.w == width) && (ee->prop.step.h == height)) return;
+ ee->prop.step.w = width;
+ ee->prop.step.h = height;
+ ecore_win32_window_size_step_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ width, height);
+}
+
+static void
+_ecore_evas_win32_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+#if 0
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (obj == NULL)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ ecore_win32_window_cursor_show(ee->prop.window, 1);
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+
+ ecore_win32_window_cursor_show(ee->prop.window, 0);
+
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+#endif
+}
+
+static void
+_ecore_evas_win32_focus_set(Ecore_Evas *ee, int on EINA_UNUSED)
+{
+ ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window);
+}
+
+static void
+_ecore_evas_win32_iconified_set(Ecore_Evas *ee, int on)
+{
+/* if (((ee->prop.borderless) && (on)) || */
+/* ((!ee->prop.borderless) && (!on))) return; */
+ ee->prop.iconified = on;
+ ecore_win32_window_iconified_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ ee->prop.iconified);
+}
+
+static void
+_ecore_evas_win32_borderless_set(Ecore_Evas *ee, int on)
+{
+ if (((ee->prop.borderless) && (on)) ||
+ ((!ee->prop.borderless) && (!on))) return;
+ ee->prop.borderless = on;
+ ecore_win32_window_borderless_set((struct _Ecore_Win32_Window *)ee->prop.window,
+ ee->prop.borderless);
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ if (!strcmp(ee->driver, "software_gdi"))
+ {
+ Evas_Engine_Info_Software_Gdi *einfo;
+
+ einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.borderless = ee->prop.borderless;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ if (ee->prop.borderless)
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */
+}
+
+static void
+_ecore_evas_win32_override_set(Ecore_Evas *ee, int on)
+{
+ struct _Ecore_Win32_Window *window;
+
+ INF("ecore evas override set");
+
+ window = (struct _Ecore_Win32_Window *)ee->prop.window;
+
+ if (ee->prop.override == on) return;
+ if (ee->should_be_visible) ecore_win32_window_hide(window);
+ /* FIXME: use borderless_set for now */
+ ecore_win32_window_borderless_set(window, on);
+ if (ee->should_be_visible) ecore_win32_window_show(window);
+ if (ee->prop.focused) ecore_win32_window_focus(window);
+ ee->prop.override = on;
+}
+
+static void
+_ecore_evas_win32_fullscreen_set(Ecore_Evas *ee, int on)
+{
+ struct _Ecore_Win32_Window *window;
+
+ INF("ecore evas fullscreen set");
+
+ if ((ee->engine.win32.state.fullscreen && on) ||
+ (!ee->engine.win32.state.fullscreen && !on))
+ return;
+
+ ee->engine.win32.state.fullscreen = on;
+ ee->prop.fullscreen = on;
+
+ window = (struct _Ecore_Win32_Window *)ee->prop.window;
+
+ if (on != 0)
+ {
+ ecore_win32_window_fullscreen_set(window, on);
+ }
+ else
+ {
+ ecore_win32_window_fullscreen_set(window, on);
+ }
+
+ /* Nothing to be done for the GDI backend at the evas level */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWRE_DDRAW
+ if (strcmp(ee->driver, "software_ddraw") == 0)
+ {
+ Evas_Engine_Info_Software_DDraw *einfo;
+
+ einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ecore_evas_get(ee));
+ if (einfo)
+ {
+ einfo->info.fullscreen = !!on;
+/* einfo->info.layered = window->shape.layered; */
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */
+
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+ if (strcmp(ee->driver, "direct3d") == 0)
+ {
+ Evas_Engine_Info_Direct3D *einfo;
+
+ einfo = (Evas_Engine_Info_Direct3D *)evas_engine_info_get(ecore_evas_get(ee));
+ if (einfo)
+ {
+ einfo->info.fullscreen = !!on;
+ einfo->info.layered = window->shape.layered;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+ }
+#endif /* BUILD_ECORE_EVAS_DIRECT3D */
+}
+static void
+_ecore_evas_win32_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ alpha = !!alpha;
+ if ((ee->alpha == alpha)) return;
+
+ if (!strcmp(ee->driver, "software_gdi"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+ Evas_Engine_Info_Software_Gdi *einfo;
+
+ einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+
+ ee->shaped = 0;
+ ee->alpha = alpha;
+ /* ecore_win32_window_free(ee->prop.window); */
+ /* ecore_event_window_unregister(ee->prop.window); */
+ /* if (ee->alpha) */
+ /* { */
+ /* if (ee->prop.override) */
+ /* ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); */
+ /* else */
+ /* ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); */
+ /* if (!ee->engine.x.mask) */
+ /* ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); */
+ /* } */
+ /* else */
+ /* { */
+ /* if (ee->prop.override) */
+ /* ee->prop.window = ecore_win32_window_override_new(ee->engine.win32.win_root, */
+ /* ee->req.x, */
+ /* ee->req.y, */
+ /* ee->req.w, */
+ /* ee->req.h); */
+ /* else */
+ /* ee->prop.window = ecore_win32_window_new(ee->engine.win32.win_root, */
+ /* ee->req.x, */
+ /* ee->req.y, */
+ /* ee->req.w, */
+ /* ee->req.h); */
+ /* if (ee->engine.win32.mask) ecore_x_pixmap_free(ee->engine.x.mask); */
+ /* ee->engine.win32.mask = 0; */
+ /* ecore_win32_window_shape_input_mask_set(ee->prop.window, 0); */
+ /* } */
+
+ /* einfo->info.destination_alpha = alpha; */
+ einfo->info.region = alpha;
+
+// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+// ee->engine.x.mask = 0;
+ /* einfo->info.mask = ee->engine.win32.mask; */
+ /* einfo->info.drawable = ee->prop.window; */
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
+ /* ecore_win32_window_shape_mask_set(ee->prop.window, 0); */
+ /* ecore_event_window_register(ee->prop.window, ee, ee->evas, */
+ /* (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, */
+ /* (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, */
+ /* (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, */
+ /* (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); */
+ if (ee->prop.borderless)
+ ecore_win32_window_borderless_set((struct _Ecore_Win32_Window *)ee->prop.window, ee->prop.borderless);
+ if (ee->visible) ecore_win32_window_show((struct _Ecore_Win32_Window *)ee->prop.window);
+ if (ee->prop.focused) ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window);
+ if (ee->prop.title)
+ {
+ ecore_win32_window_title_set((struct _Ecore_Win32_Window *)ee->prop.window, ee->prop.title);
+ /* ecore_win32_name_set(ee->prop.window, ee->prop.title); */
+ }
+ ecore_win32_window_type_set((struct _Ecore_Win32_Window *)ee->prop.window, ECORE_WIN32_WINDOW_TYPE_NORMAL);
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */
+ }
+}
+
+static void
+_ecore_evas_win32_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi)
+{
+ HDC dc;
+
+ dc = GetDC(NULL);
+ if (!dc)
+ {
+ if (xdpi) *xdpi = 0;
+ if (ydpi) *ydpi = 0;
+ return;
+ }
+
+ if (xdpi) *xdpi = GetDeviceCaps(dc, LOGPIXELSX);
+ if (ydpi) *ydpi = GetDeviceCaps(dc, LOGPIXELSY);
+
+ /*
+ * Alternative (to test)
+ int width_mm;
+ int height_mm;
+ int width_px;
+ int height_px;
+
+ width_mm = GetDeviceCaps(dc, HORZSIZE);
+ height_mm = GetDeviceCaps(dc, VERTSIZE);
+ width_px = GetDeviceCaps(dc, HORZRES);
+ height_px = GetDeviceCaps(dc, VERTRES);
+
+ *xdpi = (width_px * 254) / (width_mm * 10);
+ *ydpi = (height_px * 254) / (height_mm * 10);
+
+ code with LOGPIXELS gives 96x96
+ code with the computation gives 101x77
+
+ */
+
+ ReleaseDC(NULL, dc);
+}
+
+static Ecore_Evas_Engine_Func _ecore_win32_engine_func =
+{
+ _ecore_evas_win32_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_win32_callback_delete_request_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_win32_move,
+ NULL,
+ _ecore_evas_win32_resize,
+ _ecore_evas_win32_move_resize,
+ _ecore_evas_win32_rotation_set,
+ _ecore_evas_win32_shaped_set,
+ _ecore_evas_win32_show,
+ _ecore_evas_win32_hide,
+ _ecore_evas_win32_raise,
+ _ecore_evas_win32_lower,
+ _ecore_evas_win32_activate,
+ _ecore_evas_win32_title_set,
+ NULL, /* _ecore_evas_x_name_class_set */
+ _ecore_evas_win32_size_min_set,
+ _ecore_evas_win32_size_max_set,
+ _ecore_evas_win32_size_base_set,
+ _ecore_evas_win32_size_step_set,
+ _ecore_evas_win32_cursor_set,
+ NULL, /* _ecore_evas_x_layer_set */
+ _ecore_evas_win32_focus_set,
+ _ecore_evas_win32_iconified_set,
+ _ecore_evas_win32_borderless_set,
+ _ecore_evas_win32_override_set,
+ NULL,
+ _ecore_evas_win32_fullscreen_set,
+ NULL, /* _ecore_evas_x_avoid_damage_set */
+ NULL, /* _ecore_evas_x_withdrawn_set */
+ NULL, /* _ecore_evas_x_sticky_set */
+ NULL, /* _ecore_evas_x_ignore_events_set */
+ _ecore_evas_win32_alpha_set,
+ NULL, //transparent
+ NULL, // profiles_set
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, // render
+ NULL, // screen_geometry_get
+ _ecore_evas_win32_screen_dpi_get
+};
+
+#endif /* BUILD_ECORE_EVAS_WIN32 */
+
+/* API */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+static int
+_ecore_evas_engine_software_gdi_init(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Software_Gdi *einfo;
+ const char *driver;
+ int rmethod;
+
+ driver = "software_gdi";
+
+ rmethod = evas_render_method_lookup(driver);
+ if (!rmethod)
+ return 0;
+
+ ee->driver = driver;
+ evas_output_method_set(ee->evas, rmethod);
+
+ einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ /* FIXME: REDRAW_DEBUG missing for now */
+ einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window;
+ einfo->info.depth = ecore_win32_screen_depth_get();
+ einfo->info.rotation = 0;
+ einfo->info.borderless = 0;
+ einfo->info.fullscreen = 0;
+ einfo->info.region = 0;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+static int
+_ecore_evas_engine_software_ddraw_init(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Software_DDraw *einfo;
+ const char *driver;
+ int rmethod;
+
+ driver = "software_ddraw";
+
+ rmethod = evas_render_method_lookup(driver);
+ if (!rmethod)
+ return 0;
+
+ ee->driver = driver;
+ evas_output_method_set(ee->evas, rmethod);
+
+ einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ /* FIXME: REDRAW_DEBUG missing for now */
+ einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window;
+ einfo->info.depth = ecore_win32_screen_depth_get();
+ einfo->info.rotation = 0;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */
+
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+static int
+_ecore_evas_engine_direct3d_init(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_Direct3D *einfo;
+ const char *driver;
+ int rmethod;
+
+ driver = "direct3d";
+
+ rmethod = evas_render_method_lookup(driver);
+ if (!rmethod)
+ return 0;
+
+ ee->driver = driver;
+ evas_output_method_set(ee->evas, rmethod);
+
+ einfo = (Evas_Engine_Info_Direct3D *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ /* FIXME: REDRAW_DEBUG missing for now */
+ einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window;
+ einfo->info.depth = ecore_win32_screen_depth_get();
+ einfo->info.rotation = 0;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* BUILD_ECORE_EVAS_DIRECT3D */
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+static int
+_ecore_evas_engine_opengl_glew_init(Ecore_Evas *ee)
+{
+ Evas_Engine_Info_GL_Glew *einfo;
+ const char *driver;
+ int rmethod;
+
+ driver = "gl_glew";
+
+ rmethod = evas_render_method_lookup(driver);
+ if (!rmethod)
+ return 0;
+
+ ee->driver = driver;
+ evas_output_method_set(ee->evas, rmethod);
+
+ einfo = (Evas_Engine_Info_GL_Glew *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ /* FIXME: REDRAW_DEBUG missing for now */
+ einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window;
+ einfo->info.depth = ecore_win32_screen_depth_get();
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ }
+ else
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */
+
+#ifdef BUILD_ECORE_EVAS_WIN32
+static Ecore_Evas *
+_ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee),
+ Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ Ecore_Evas *ee;
+
+ if (!ecore_win32_init())
+ return NULL;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee)
+ return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_win32_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_win32_engine_func;
+
+ if (width < 1) width = 1;
+ if (height < 1) height = 1;
+ ee->x = x;
+ ee->y = y;
+ ee->w = width;
+ ee->h = height;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ /* FIXME: sticky to add */
+ ee->prop.window = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_size_set(ee->evas, width, height);
+ evas_output_viewport_set(ee->evas, 0, 0, width, height);
+
+ ee->engine.win32.parent = parent;
+ ee->prop.window = (Ecore_Window)ecore_win32_window_new(parent, x, y, width, height);
+ if (!ee->prop.window)
+ {
+ _ecore_evas_win32_shutdown();
+ free(ee);
+ return NULL;
+ }
+
+ if (!_ecore_evas_engine_init(ee))
+ {
+ _ecore_evas_win32_shutdown();
+ free(ee);
+ return NULL;
+ }
+
+ ee->engine.func->fn_render = _ecore_evas_win32_render;
+ _ecore_evas_register(ee);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ return ee;
+}
+
+#endif /* BUILD_ECORE_EVAS_WIN32 */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI
+
+EAPI Ecore_Evas *
+ecore_evas_software_gdi_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ return _ecore_evas_win32_new_internal(_ecore_evas_engine_software_gdi_init,
+ parent,
+ x,
+ y,
+ width,
+ height);
+}
+
+#else
+
+EAPI Ecore_Evas *
+ecore_evas_software_gdi_new(Ecore_Win32_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_GDI */
+
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW
+
+EAPI Ecore_Evas *
+ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ return _ecore_evas_win32_new_internal(_ecore_evas_engine_software_ddraw_init,
+ parent,
+ x,
+ y,
+ width,
+ height);
+}
+
+#else
+
+EAPI Ecore_Evas *
+ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_DDRAW */
+
+
+EAPI Ecore_Evas *
+ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+#ifdef BUILD_ECORE_EVAS_DIRECT3D
+
+EAPI Ecore_Evas *
+ecore_evas_direct3d_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ return _ecore_evas_win32_new_internal(_ecore_evas_engine_direct3d_init,
+ parent,
+ x,
+ y,
+ width,
+ height);
+}
+
+#else
+
+EAPI Ecore_Evas *
+ecore_evas_direct3d_new(Ecore_Win32_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif /* ! BUILD_ECORE_EVAS_DIRECT3D */
+
+
+#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
+
+EAPI Ecore_Evas *
+ecore_evas_gl_glew_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ return _ecore_evas_win32_new_internal(_ecore_evas_engine_opengl_glew_init,
+ parent,
+ x,
+ y,
+ width,
+ height);
+}
+
+#else
+
+EAPI Ecore_Evas *
+ecore_evas_gl_glew_new(Ecore_Win32_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */
+
+
+#ifdef BUILD_ECORE_EVAS_WIN32
+
+EAPI Ecore_Win32_Window *
+ecore_evas_win32_window_get(const Ecore_Evas *ee)
+{
+ return (Ecore_Win32_Window *) ecore_evas_window_get(ee);
+}
+
+#else
+
+EAPI Ecore_Win32_Window *
+ecore_evas_win32_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return NULL;
+}
+
+#endif /* BUILD_ECORE_EVAS_WIN32 */
diff --git a/src/lib/ecore_evas/ecore_evas_wince.c b/src/lib/ecore_evas/ecore_evas_wince.c
new file mode 100644
index 0000000000..142a85059c
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_wince.c
@@ -0,0 +1,67 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h> /* for NULL */
+
+#include <Ecore.h>
+#include "ecore_private.h"
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+EAPI Ecore_Evas *
+ecore_evas_software_wince_new(Ecore_WinCE_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_wince_fb_new(Ecore_WinCE_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_wince_gapi_new(Ecore_WinCE_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_wince_ddraw_new(Ecore_WinCE_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_wince_gdi_new(Ecore_WinCE_Window *parent EINA_UNUSED,
+ int x EINA_UNUSED,
+ int y EINA_UNUSED,
+ int width EINA_UNUSED,
+ int height EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_WinCE_Window *
+ecore_evas_software_wince_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return NULL;
+}
diff --git a/src/lib/ecore_evas/ecore_evas_x.c b/src/lib/ecore_evas/ecore_evas_x.c
new file mode 100644
index 0000000000..d94f055319
--- /dev/null
+++ b/src/lib/ecore_evas/ecore_evas_x.c
@@ -0,0 +1,3663 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include "ecore_evas_private.h"
+#include "Ecore_Evas.h"
+
+#ifdef BUILD_ECORE_EVAS_X11
+static int _ecore_evas_init_count = 0;
+
+static Ecore_Event_Handler *ecore_evas_event_handlers[13];
+
+static int leader_ref = 0;
+static Ecore_X_Window leader_win = 0;
+
+static void
+_ecore_evas_x_hints_update(Ecore_Evas *ee)
+{
+ ecore_x_icccm_hints_set
+ (ee->prop.window,
+ !ee->prop.focus_skip /* accepts_focus */,
+ ee->prop.iconified ? ECORE_X_WINDOW_STATE_HINT_ICONIC :
+ ee->prop.withdrawn ? ECORE_X_WINDOW_STATE_HINT_WITHDRAWN :
+ ECORE_X_WINDOW_STATE_HINT_NORMAL /* initial_state */,
+ 0 /* icon_pixmap */,
+ 0 /* icon_mask */,
+ 0 /* icon_window */,
+ ee->prop.group_ee_win /* window_group */,
+ ee->prop.urgent /* is_urgent */);
+}
+
+static void
+_ecore_evas_x_group_leader_set(Ecore_Evas *ee)
+{
+ leader_ref++;
+ if (leader_ref == 1)
+ {
+ char *id = NULL;
+
+ leader_win =
+ ecore_x_window_override_new(ee->engine.x.win_root, 1234, 5678, 1, 2);
+ ecore_x_window_defaults_set(leader_win);
+ if ((id = getenv("DESKTOP_STARTUP_ID")))
+ ecore_x_netwm_startup_id_set(leader_win,id);
+ ecore_x_icccm_client_leader_set(leader_win, leader_win);
+ }
+ ee->engine.x.leader = leader_win;
+ ecore_x_icccm_client_leader_set(ee->prop.window, leader_win);
+}
+
+static void
+_ecore_evas_x_group_leader_unset(Ecore_Evas *ee)
+{
+ ecore_x_window_prop_property_del(ee->prop.window,
+ ECORE_X_ATOM_WM_CLIENT_LEADER);
+ if (ee->engine.x.leader == leader_win)
+ {
+ leader_ref--;
+ if (leader_ref <= 0)
+ {
+ ecore_x_window_free(leader_win);
+ leader_win = 0;
+ }
+ ee->engine.x.leader = 0;
+ }
+}
+
+static void
+_ecore_evas_x_group_leader_update(Ecore_Evas *ee)
+{
+ if (ee->engine.x.leader)
+ ecore_x_icccm_client_leader_set(ee->prop.window, ee->engine.x.leader);
+}
+
+static void
+_ecore_evas_x_protocols_set(Ecore_Evas *ee)
+{
+ Ecore_X_Atom protos[3];
+ unsigned int num = 0, tmp = 0;
+
+ if (ee->func.fn_delete_request)
+ protos[num++] = ECORE_X_ATOM_WM_DELETE_WINDOW;
+ protos[num++] = ECORE_X_ATOM_NET_WM_PING;
+ protos[num++] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+ ecore_x_icccm_protocol_atoms_set(ee->prop.window, protos, num);
+
+ if (!ee->engine.x.netwm_sync_counter)
+ ee->engine.x.netwm_sync_counter = ecore_x_sync_counter_new(0);
+
+ tmp = ee->engine.x.netwm_sync_counter;
+ ecore_x_window_prop_card32_set(ee->prop.window,
+ ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
+ &tmp, 1);
+}
+
+static void
+_ecore_evas_x_sync_set(Ecore_Evas *ee)
+{
+ Ecore_X_Sync_Counter sync_counter = ee->engine.x.sync_counter;
+
+ if (((ee->should_be_visible) || (ee->visible)) &&
+ ((ecore_x_e_comp_sync_supported_get(ee->engine.x.win_root)) &&
+ (!ee->no_comp_sync) && (_ecore_evas_app_comp_sync)))
+ {
+ if (!ee->engine.x.sync_counter)
+ ee->engine.x.sync_counter = ecore_x_sync_counter_new(0);
+ }
+ else
+ {
+ if (ee->engine.x.sync_counter)
+ {
+ ecore_x_sync_counter_free(ee->engine.x.sync_counter);
+ ee->engine.x.sync_val = 0;
+ }
+ ee->engine.x.sync_counter = 0;
+ }
+ if (sync_counter != ee->engine.x.sync_counter)
+ ecore_x_e_comp_sync_counter_set(ee->prop.window, ee->engine.x.sync_counter);
+}
+
+static void
+_ecore_evas_x_sync_clear(Ecore_Evas *ee)
+{
+ if (!ee->engine.x.sync_counter) return;
+ ecore_x_sync_counter_free(ee->engine.x.sync_counter);
+ ee->engine.x.sync_val = 0;
+ ee->engine.x.sync_counter = 0;
+}
+
+# ifdef BUILD_ECORE_EVAS_OPENGL_X11
+static Ecore_X_Window
+_ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, int w, int h, int override, int argb, const int *opt)
+{
+ Evas_Engine_Info_GL_X11 *einfo;
+ Ecore_X_Window win;
+
+ einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ int screen;
+
+ if (opt)
+ {
+ int op;
+
+ for (op = 0; opt[op]; op++)
+ {
+ if (opt[op] == ECORE_EVAS_GL_X11_OPT_INDIRECT)
+ {
+ op++;
+ einfo->indirect = opt[op];
+ }
+ else if (opt[op] == ECORE_EVAS_GL_X11_OPT_VSYNC)
+ {
+ op++;
+ einfo->vsync = opt[op];
+ }
+#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS
+ else if (opt[op] == ECORE_EVAS_GL_X11_OPT_SWAP_MODE)
+ {
+ op++;
+ if ((evas_version->major >= 1) &&
+ (evas_version->minor >= 7) &&
+ (evas_version->micro >= 99))
+ einfo->swap_mode = opt[op];
+ }
+#endif
+ }
+ }
+
+ /* FIXME: this is inefficient as its 1 or more round trips */
+ screen = ecore_x_screen_index_get(ecore_x_default_screen_get());
+ if (ecore_x_screen_count_get() > 1)
+ {
+ Ecore_X_Window *roots;
+ int num, i;
+
+ num = 0;
+ roots = ecore_x_window_root_list(&num);
+ if (roots)
+ {
+ Ecore_X_Window root;
+
+ root = ecore_x_window_root_get(parent);
+ for (i = 0; i < num; i++)
+ {
+ if (root == roots[i])
+ {
+ screen = i;
+ break;
+ }
+ }
+ free(roots);
+ }
+ }
+
+ einfo->info.display = ecore_x_display_get();
+ einfo->info.screen = screen;
+
+ einfo->info.destination_alpha = argb;
+
+ einfo->info.visual = einfo->func.best_visual_get(einfo);
+ einfo->info.colormap = einfo->func.best_colormap_get(einfo);
+ einfo->info.depth = einfo->func.best_depth_get(einfo);
+
+ if ((!einfo->info.visual) ||
+ (!einfo->info.colormap) || (!einfo->info.depth))
+ {
+ WRN("OpenGL X11 init engine '%s' failed - no visual, colormap or depth.", ee->driver);
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ return 0;
+ }
+ }
+
+ if (argb)
+ {
+ if (override)
+ win = ecore_x_window_override_argb_new(parent, x, y, w, h);
+ else
+ win = ecore_x_window_argb_new(parent, x, y, w, h);
+ }
+ else
+ {
+ if (override)
+ win = ecore_x_window_override_new(parent, x, y, w, h);
+ else
+ win = ecore_x_window_new(parent, x, y, w, h);
+ }
+
+ ecore_x_window_pixel_gravity_set(win, ECORE_X_GRAVITY_FORGET);
+
+ /* attr.backing_store = NotUseful; */
+ /* attr.override_redirect = override; */
+ /* attr.colormap = einfo->info.colormap; */
+ /* attr.border_pixel = 0; */
+ /* attr.background_pixmap = None; */
+ /* attr.event_mask = */
+ /* KeyPressMask | KeyReleaseMask | */
+ /* ExposureMask | ButtonPressMask | ButtonReleaseMask | */
+ /* EnterWindowMask | LeaveWindowMask | */
+ /* PointerMotionMask | StructureNotifyMask | VisibilityChangeMask | */
+ /* FocusChangeMask | PropertyChangeMask | ColormapChangeMask; */
+ /* attr.bit_gravity = ForgetGravity; */
+
+ /* win = */
+ /* XCreateWindow(einfo->info.display, parent, x, y, w, h, 0, */
+ /* einfo->info.depth, InputOutput, einfo->info.visual, */
+ /* CWBackingStore | CWColormap | CWBackPixmap | */
+ /* CWBorderPixel | CWBitGravity | CWEventMask | */
+ /* CWOverrideRedirect, &attr); */
+
+ einfo->info.drawable = win;
+
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ecore_x_window_free(win);
+ return 0;
+ }
+ }
+ else
+ win = 0;
+
+ return win;
+}
+#endif
+
+static int
+_ecore_evas_x_render(Ecore_Evas *ee)
+{
+ int rend = 0;
+ Eina_List *updates = NULL;
+ Eina_List *ll;
+ Ecore_Evas *ee2;
+
+ if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) &&
+ (ee->engine.x.sync_counter) && (!ee->engine.x.sync_began) &&
+ (!ee->engine.x.sync_cancel))
+ return 0;
+
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2)
+ {
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ }
+
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+ updates = evas_render_updates(ee->evas);
+ if (ee->prop.avoid_damage)
+ {
+ if (ee->engine.x.using_bg_pixmap)
+ {
+ if (updates)
+ {
+ Eina_List *l = NULL;
+ Eina_Rectangle *r;
+
+ EINA_LIST_FOREACH(updates, l, r)
+ ecore_x_window_area_clear(ee->prop.window,
+ r->x, r->y, r->w, r->h);
+ if (ee->shaped)
+ {
+ ecore_x_window_shape_mask_set(ee->prop.window,
+ ee->engine.x.mask);
+ }
+ if (ee->alpha)
+ {
+// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask);
+ }
+ _ecore_evas_idle_timeout_update(ee);
+ rend = 1;
+ }
+ }
+ else
+ {
+ if (updates)
+ {
+ Eina_List *l = NULL;
+ Eina_Rectangle *r;
+
+ EINA_LIST_FOREACH(updates, l, r)
+ {
+ Ecore_X_Rectangle rect;
+ Ecore_X_XRegion *tmpr;
+
+ if (!ee->engine.x.damages)
+ ee->engine.x.damages = ecore_x_xregion_new();
+ tmpr = ecore_x_xregion_new();
+ if (ee->rotation == 0)
+ {
+ rect.x = r->x;
+ rect.y = r->y;
+ rect.width = r->w;
+ rect.height = r->h;
+ }
+ else if (ee->rotation == 90)
+ {
+ rect.x = r->y;
+ rect.y = ee->h - r->x - r->w;
+ rect.width = r->h;
+ rect.height = r->w;
+ }
+ else if (ee->rotation == 180)
+ {
+ rect.x = ee->w - r->x - r->w;
+ rect.y = ee->h - r->y - r->h;
+ rect.width = r->w;
+ rect.height = r->h;
+ }
+ else if (ee->rotation == 270)
+ {
+ rect.x = ee->w - r->y - r->h;
+ rect.y = r->x;
+ rect.width = r->h;
+ rect.height = r->w;
+ }
+ ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages,
+ &rect);
+ ecore_x_xregion_free(ee->engine.x.damages);
+ ee->engine.x.damages = tmpr;
+ }
+ if (ee->engine.x.damages)
+ {
+ if (ee->shaped)
+ {
+
+ /* if we have a damage pixmap - we can avoid exposures by
+ * disabling them just for setting the mask */
+ ecore_x_event_mask_unset(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE);
+ ecore_x_window_shape_mask_set(ee->prop.window,
+ ee->engine.x.mask);
+ /* and re-enable them again */
+ ecore_x_event_mask_set(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE);
+ }
+ ecore_x_xregion_set(ee->engine.x.damages, ee->engine.x.gc);
+ ecore_x_pixmap_paste(ee->engine.x.pmap, ee->prop.window,
+ ee->engine.x.gc, 0, 0, ee->w, ee->h,
+ 0, 0);
+ ecore_x_xregion_free(ee->engine.x.damages);
+ ee->engine.x.damages = NULL;
+ }
+ _ecore_evas_idle_timeout_update(ee);
+ rend = 1;
+ }
+ }
+ }
+ else if (((ee->visible) && (ee->draw_ok)) ||
+ ((ee->should_be_visible) && (ee->prop.fullscreen)) ||
+ ((ee->should_be_visible) && (ee->prop.override)))
+ {
+ if (updates)
+ {
+ if (ee->shaped)
+ {
+ ecore_x_window_shape_mask_set(ee->prop.window,
+ ee->engine.x.mask);
+ }
+ if (ee->alpha)
+ {
+// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask);
+ }
+ _ecore_evas_idle_timeout_update(ee);
+ rend = 1;
+ }
+ }
+ else
+ evas_norender(ee->evas);
+ evas_render_updates_free(updates);
+
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+/*
+ if (rend)
+ {
+ static int frames = 0;
+ static double t0 = 0.0;
+ double t, td;
+
+ t = ecore_time_get();
+ frames++;
+ if ((t - t0) > 1.0)
+ {
+ td = t - t0;
+ printf("FPS: %3.3f\n", (double)frames / td);
+ frames = 0;
+ t0 = t;
+ }
+ }
+ */
+
+ return rend;
+}
+
+static void
+_ecore_evas_x_resize_shape(Ecore_Evas *ee)
+{
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ unsigned int foreground;
+ Ecore_X_GC gc;
+
+ if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+ ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1);
+ foreground = 0;
+ gc = ecore_x_gc_new(ee->engine.x.mask,
+ ECORE_X_GC_VALUE_MASK_FOREGROUND,
+ &foreground);
+ ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc,
+ 0, 0, ee->w, ee->h);
+ ecore_x_gc_free(gc);
+ einfo->info.mask = ee->engine.x.mask;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
+ }
+}
+
+/* TODO: we need to make this work for all the states, not just sticky */
+static Eina_Bool
+_ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Property *e;
+ int state_change = 0;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (e->atom == ECORE_X_ATOM_NET_WM_STATE)
+ {
+ unsigned int i, num;
+ Ecore_X_Window_State *state;
+ struct {
+ struct {
+ unsigned char modal : 1;
+ unsigned char sticky : 1;
+ unsigned char maximized_v : 1;
+ unsigned char maximized_h : 1;
+ unsigned char shaded : 1;
+ unsigned char skip_taskbar : 1;
+ unsigned char skip_pager : 1;
+ unsigned char fullscreen : 1;
+ unsigned char above : 1;
+ unsigned char below : 1;
+ } x;
+ struct {
+ char modal : 1;
+ char maximized : 1;
+ char sticky : 1;
+ char fullscreen : 1;
+ char focus_skip : 1;
+ } prop;
+ } prev;
+
+ prev.x.modal = ee->engine.x.state.modal;
+ prev.x.sticky = ee->engine.x.state.sticky;
+ prev.x.maximized_v = ee->engine.x.state.maximized_v;
+ prev.x.maximized_h = ee->engine.x.state.maximized_h;
+ prev.x.shaded = ee->engine.x.state.shaded;
+ prev.x.skip_taskbar = ee->engine.x.state.skip_taskbar;
+ prev.x.skip_pager = ee->engine.x.state.skip_pager;
+ prev.x.fullscreen = ee->engine.x.state.fullscreen;
+ prev.x.above = ee->engine.x.state.above;
+ prev.x.below = ee->engine.x.state.below;
+
+ prev.prop.modal = ee->prop.modal;
+ prev.prop.maximized = ee->prop.maximized;
+ prev.prop.sticky = ee->prop.sticky;
+ prev.prop.fullscreen = ee->prop.fullscreen;
+ prev.prop.focus_skip = ee->prop.focus_skip;
+
+ ee->engine.x.state.modal = 0;
+ ee->engine.x.state.sticky = 0;
+ ee->engine.x.state.maximized_v = 0;
+ ee->engine.x.state.maximized_h = 0;
+ ee->engine.x.state.shaded = 0;
+ ee->engine.x.state.skip_taskbar = 0;
+ ee->engine.x.state.skip_pager = 0;
+ ee->engine.x.state.fullscreen = 0;
+ ee->engine.x.state.above = 0;
+ ee->engine.x.state.below = 0;
+
+ ee->prop.modal = 0;
+ ee->prop.maximized = 0;
+ ee->prop.sticky = 0;
+ ee->prop.fullscreen = 0;
+ ee->prop.focus_skip = 0;
+
+ ecore_x_netwm_window_state_get(e->win, &state, &num);
+ if (state)
+ {
+ for (i = 0; i < num; i++)
+ {
+ switch (state[i])
+ {
+ case ECORE_X_WINDOW_STATE_MODAL:
+ ee->engine.x.state.modal = 1;
+ ee->prop.modal = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_STICKY:
+ ee->prop.sticky = 1;
+ ee->engine.x.state.sticky = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
+ ee->engine.x.state.maximized_v = 1;
+ ee->prop.maximized = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
+ ee->engine.x.state.maximized_h = 1;
+ ee->prop.maximized = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_SHADED:
+ ee->engine.x.state.shaded = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
+ ee->engine.x.state.skip_taskbar = 1;
+ ee->prop.focus_skip = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_SKIP_PAGER:
+ ee->engine.x.state.skip_pager = 1;
+ ee->prop.focus_skip = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_FULLSCREEN:
+ ee->prop.fullscreen = 1;
+ ee->engine.x.state.fullscreen = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_ABOVE:
+ ee->engine.x.state.above = 1;
+ break;
+ case ECORE_X_WINDOW_STATE_BELOW:
+ ee->engine.x.state.below = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ free(state);
+ }
+ if (
+// (prev.x.modal != ee->engine.x.state.modal) ||
+ (prev.x.sticky != ee->engine.x.state.sticky) ||
+ (prev.x.maximized_v != ee->engine.x.state.maximized_v) ||
+ (prev.x.maximized_h != ee->engine.x.state.maximized_h) ||
+// (prev.x.shaded != ee->engine.x.state.shaded) ||
+// (prev.x.skip_taskbar != ee->engine.x.state.skip_taskbar) ||
+// (prev.x.skip_pager != ee->engine.x.state.skip_pager) ||
+ (prev.x.fullscreen != ee->engine.x.state.fullscreen) ||
+// (prev.x.above != ee->engine.x.state.above) ||
+// (prev.x.below != ee->engine.x.state.below) ||
+// (prev.prop.modal != ee->prop.modal) ||
+ (prev.prop.maximized != ee->prop.maximized) ||
+ (prev.prop.sticky != ee->prop.sticky) ||
+ (prev.prop.fullscreen != ee->prop.fullscreen) ||
+ (prev.prop.focus_skip != ee->prop.focus_skip))
+ state_change = 1;
+ }
+ else if (e->atom == ECORE_X_ATOM_WM_STATE)
+ {
+ Ecore_X_Window_State_Hint state;
+
+ // handle WM_STATE changes
+ state = ecore_x_icccm_state_get(e->win);
+ switch (state)
+ {
+ case ECORE_X_WINDOW_STATE_HINT_WITHDRAWN:
+ if ((!ee->prop.withdrawn) || (ee->prop.iconified))
+ {
+ state_change = 1;
+ ee->prop.withdrawn = 1;
+ ee->prop.iconified = 0;
+ }
+ break;
+ case ECORE_X_WINDOW_STATE_HINT_ICONIC:
+ if ((!ee->prop.iconified) || (ee->prop.withdrawn))
+ {
+ state_change = 1;
+ ee->prop.iconified = 1;
+ ee->prop.withdrawn = 0;
+ }
+ break;
+ case ECORE_X_WINDOW_STATE_HINT_NORMAL:
+ if ((ee->prop.iconified) || (ee->prop.withdrawn))
+ {
+ state_change = 1;
+ ee->prop.iconified = 0;
+ ee->prop.withdrawn = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if (e->atom == ECORE_X_ATOM_E_PROFILE)
+ {
+ char *p = ecore_x_e_window_profile_get(e->win);
+ if ((p) && (ee->prop.profile))
+ {
+ if (strcmp(p, ee->prop.profile) != 0)
+ {
+ free(ee->prop.profile);
+ ee->prop.profile = strdup(p);
+ state_change = 1;
+ }
+ }
+ else if ((!p) && (ee->prop.profile))
+ {
+ free(ee->prop.profile);
+ ee->prop.profile = NULL;
+ state_change = 1;
+ }
+ else if ((p) && (!ee->prop.profile))
+ {
+ ee->prop.profile = strdup(p);
+ state_change = 1;
+ }
+
+ if (p)
+ free(p);
+ }
+
+ if (state_change)
+ {
+ if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_visibility_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Visibility_Change *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+// printf("VIS CHANGE OBSCURED: %p %i\n", ee, e->fully_obscured);
+ if (e->fully_obscured)
+ {
+ /* FIXME: round trip */
+ if (!ecore_x_screen_is_composited(ee->engine.x.screen_num))
+ ee->draw_ok = 0;
+ }
+ else
+ ee->draw_ok = 1;
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_client_message(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Client_Message *e;
+
+ e = event;
+ if (e->format != 32) return ECORE_CALLBACK_PASS_ON;
+ if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_BEGIN)
+ {
+ ee = ecore_event_window_match(e->data.l[0]);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->data.l[0] != (long)ee->prop.window)
+ return ECORE_CALLBACK_PASS_ON;
+ if (!ee->engine.x.sync_began)
+ {
+ // qeue a damage + draw. work around an event re-ordering thing.
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ ee->engine.x.sync_began = 1;
+ ee->engine.x.sync_cancel = 0;
+ }
+ else if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_END)
+ {
+ ee = ecore_event_window_match(e->data.l[0]);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->data.l[0] != (long)ee->prop.window)
+ return ECORE_CALLBACK_PASS_ON;
+ ee->engine.x.sync_began = 0;
+ ee->engine.x.sync_cancel = 0;
+ }
+ else if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_CANCEL)
+ {
+ ee = ecore_event_window_match(e->data.l[0]);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->data.l[0] != (long)ee->prop.window)
+ return ECORE_CALLBACK_PASS_ON;
+ ee->engine.x.sync_began = 0;
+ ee->engine.x.sync_cancel = 1;
+ }
+ else if ((e->message_type == ECORE_X_ATOM_WM_PROTOCOLS) &&
+ (e->data.l[0] == (int)ECORE_X_ATOM_NET_WM_SYNC_REQUEST))
+ {
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ ee->engine.x.netwm_sync_val_lo = (unsigned int)e->data.l[2];
+ ee->engine.x.netwm_sync_val_hi = (int)e->data.l[3];
+ ee->engine.x.netwm_sync_set = 1;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Mouse_In *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+/* { */
+/* time_t t; */
+/* char *ct; */
+
+/* const char *modes[] = { */
+/* "MODE_NORMAL", */
+/* "MODE_WHILE_GRABBED", */
+/* "MODE_GRAB", */
+/* "MODE_UNGRAB" */
+/* }; */
+/* const char *details[] = { */
+/* "DETAIL_ANCESTOR", */
+/* "DETAIL_VIRTUAL", */
+/* "DETAIL_INFERIOR", */
+/* "DETAIL_NON_LINEAR", */
+/* "DETAIL_NON_LINEAR_VIRTUAL", */
+/* "DETAIL_POINTER", */
+/* "DETAIL_POINTER_ROOT", */
+/* "DETAIL_DETAIL_NONE" */
+/* }; */
+/* t = time(NULL); */
+/* ct = ctime(&t); */
+/* ct[strlen(ct) - 1] = 0; */
+/* printf("@@ ->IN 0x%x 0x%x %s md=%s dt=%s\n", */
+/* e->win, e->event_win, */
+/* ct, */
+/* modes[e->mode], */
+/* details[e->detail]); */
+/* } */
+ // disable. causes more problems than it fixes
+ // if ((e->mode == ECORE_X_EVENT_MODE_GRAB) ||
+ // (e->mode == ECORE_X_EVENT_MODE_UNGRAB))
+ // return 0;
+ /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */
+ if (!ee->in)
+ {
+ if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee);
+ ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers);
+ evas_event_feed_mouse_in(ee->evas, e->time, NULL);
+ _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ ee->in = EINA_TRUE;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Mouse_Out *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
+ /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+/* { */
+/* time_t t; */
+/* char *ct; */
+
+/* const char *modes[] = { */
+/* "MODE_NORMAL", */
+/* "MODE_WHILE_GRABBED", */
+/* "MODE_GRAB", */
+/* "MODE_UNGRAB" */
+/* }; */
+/* const char *details[] = { */
+/* "DETAIL_ANCESTOR", */
+/* "DETAIL_VIRTUAL", */
+/* "DETAIL_INFERIOR", */
+/* "DETAIL_NON_LINEAR", */
+/* "DETAIL_NON_LINEAR_VIRTUAL", */
+/* "DETAIL_POINTER", */
+/* "DETAIL_POINTER_ROOT", */
+/* "DETAIL_DETAIL_NONE" */
+/* }; */
+/* t = time(NULL); */
+/* ct = ctime(&t); */
+/* ct[strlen(ct) - 1] = 0; */
+/* printf("@@ ->OUT 0x%x 0x%x %s md=%s dt=%s\n", */
+/* e->win, e->event_win, */
+/* ct, */
+/* modes[e->mode], */
+/* details[e->detail]); */
+/* } */
+ // disable. causes more problems than it fixes
+ // if ((e->mode == ECORE_X_EVENT_MODE_GRAB) ||
+ // (e->mode == ECORE_X_EVENT_MODE_UNGRAB))
+ // return 0;
+ /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */
+// printf("OUT: ee->in=%i, e->mode=%i, e->detail=%i, dount_count=%i\n",
+// ee->in, e->mode, e->detail, evas_event_down_count_get(ee->evas));
+ if (ee->in)
+ {
+ if ((evas_event_down_count_get(ee->evas) > 0) &&
+ (!((e->mode == ECORE_X_EVENT_MODE_GRAB) &&
+ (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR))))
+ return ECORE_CALLBACK_PASS_ON;
+ ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers);
+ _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
+ if (e->mode == ECORE_X_EVENT_MODE_GRAB)
+ evas_event_feed_mouse_cancel(ee->evas, e->time, NULL);
+ evas_event_feed_mouse_out(ee->evas, e->time, NULL);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+ ee->in = EINA_FALSE;
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Focus_In *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+//xx// filtering with these doesnt help
+//xx// if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) return ECORE_CALLBACK_PASS_ON;
+ ee->prop.focused = 1;
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Focus_Out *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+//xx// filtering with these doesnt help
+//xx// if (e->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON;
+
+// if (ee->prop.fullscreen)
+// ecore_x_window_focus(ee->prop.window);
+ evas_focus_out(ee->evas);
+ ee->prop.focused = 0;
+ if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_damage(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Damage *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->engine.x.using_bg_pixmap) return ECORE_CALLBACK_PASS_ON;
+// printf("EXPOSE %p [%i] %i %i %ix%i\n", ee, ee->prop.avoid_damage, e->x, e->y, e->w, e->h);
+ if (ee->prop.avoid_damage)
+ {
+ Ecore_X_Rectangle rect;
+ Ecore_X_XRegion *tmpr;
+
+ if (!ee->engine.x.damages)
+ ee->engine.x.damages = ecore_x_xregion_new();
+ tmpr = ecore_x_xregion_new();
+ rect.x = e->x;
+ rect.y = e->y;
+ rect.width = e->w;
+ rect.height = e->h;
+ ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages, &rect);
+ ecore_x_xregion_free(ee->engine.x.damages);
+ ee->engine.x.damages = tmpr;
+/* no - this breaks things badly. disable. Ecore_X_Rectangle != XRectangle - see
+ * the typedefs in x's headers and ecore_x's. also same with Region - it's a pointer in x - not an X ID
+ Ecore_X_Rectangle rect;
+ Ecore_X_XRegion *tmpr;
+
+ if (!ee->engine.x.damages) ee->engine.x.damages = ecore_x_xregion_new();
+ tmpr = ecore_x_xregion_new();
+ rect.x = e->x;
+ rect.y = e->y;
+ rect.width = e->w;
+ rect.height = e->h;
+ ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages, &rect);
+ ecore_x_xregion_free(ee->engine.x.damages);
+ ee->engine.x.damages = tmpr;
+ */
+ }
+ else
+ {
+ if (ee->rotation == 0)
+ evas_damage_rectangle_add(ee->evas, e->x, e->y, e->w, e->h);
+ else if (ee->rotation == 90)
+ evas_damage_rectangle_add(ee->evas,
+ ee->h - e->y - e->h, e->x, e->h, e->w);
+ else if (ee->rotation == 180)
+ evas_damage_rectangle_add(ee->evas, ee->w - e->x - e->w,
+ ee->h - e->y - e->h, e->w, e->h);
+ else if (ee->rotation == 270)
+ evas_damage_rectangle_add(ee->evas, e->y, ee->w - e->x - e->w,
+ e->h, e->w);
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Destroy *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->func.fn_destroy) ee->func.fn_destroy(ee);
+ _ecore_evas_x_sync_clear(ee);
+ ecore_evas_free(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_configure(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Configure *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->engine.x.direct_resize) return ECORE_CALLBACK_PASS_ON;
+
+ ee->engine.x.configure_coming = 0;
+ if ((e->from_wm) || (ee->prop.override))
+ {
+ if ((ee->x != e->x) || (ee->y != e->y))
+ {
+ ee->x = e->x;
+ ee->y = e->y;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ }
+ if ((ee->w != e->w) || (ee->h != e->h))
+ {
+ ee->w = e->w;
+ ee->h = e->h;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+ if ((ee->shaped) || (ee->alpha))
+ _ecore_evas_x_resize_shape(ee);
+ if ((ee->expecting_resize.w > 0) && (ee->expecting_resize.h > 0))
+ {
+ if ((ee->expecting_resize.w == ee->w) &&
+ (ee->expecting_resize.h == ee->h))
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_x_current_time_get());
+ ee->expecting_resize.w = 0;
+ ee->expecting_resize.h = 0;
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_delete_request(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Delete_Request *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Show *e;
+ static int first_map_bug = -1;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ /* some GL drivers are doing buffer copy in a separate thread.
+ * we need to check whether GL driver sends SYNC_DRAW_DONE msg afger copying
+ * that are required in order to exactly render. - added by gl77.lee
+ */
+ if (ee->gl_sync_draw_done < 0)
+ {
+ if (getenv("ECORE_EVAS_GL_SYNC_DRAW_DONE"))
+ ee->gl_sync_draw_done = atoi(getenv("ECORE_EVAS_GL_SYNC_DRAW_DONE"));
+ else
+ ee->gl_sync_draw_done = 0;
+ }
+ if (first_map_bug < 0)
+ {
+ char *bug = NULL;
+
+ if ((bug = getenv("ECORE_EVAS_GL_FIRST_MAP_BUG")))
+ first_map_bug = atoi(bug);
+ else
+ first_map_bug = 0;
+ }
+ if ((first_map_bug) && (!strcmp(ee->driver, "opengl_x11")))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ if (ee->visible) return ECORE_CALLBACK_PASS_ON;
+// if (ee->visible) return ECORE_CALLBACK_DONE;
+// printf("SHOW EVENT %p\n", ee);
+ ee->visible = 1;
+ if (ee->func.fn_show) ee->func.fn_show(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_evas_x_event_window_hide(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Evas *ee;
+ Ecore_X_Event_Window_Hide *e;
+
+ e = event;
+ ee = ecore_event_window_match(e->win);
+ if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
+ if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
+ if (ee->in)
+ {
+ evas_event_feed_mouse_cancel(ee->evas, e->time, NULL);
+ evas_event_feed_mouse_out(ee->evas, e->time, NULL);
+ if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee);
+ if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object);
+ ee->in = EINA_FALSE;
+ }
+ if (!ee->visible) return ECORE_CALLBACK_PASS_ON;
+// if (!ee->visible) return ECORE_CALLBACK_DONE;
+// printf("HIDE EVENT %p\n", ee);
+ ee->visible = 0;
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+/* FIXME, should be in idler */
+/* FIXME, round trip */
+static void
+_ecore_evas_x_size_pos_hints_update(Ecore_Evas *ee)
+{
+ ecore_x_icccm_size_pos_hints_set(ee->prop.window,
+ ee->prop.request_pos /*request_pos */,
+ ECORE_X_GRAVITY_NW /* gravity */,
+ ee->prop.min.w /* min_w */,
+ ee->prop.min.h /* min_h */,
+ ee->prop.max.w /* max_w */,
+ ee->prop.max.h /* max_h */,
+ ee->prop.base.w /* base_w */,
+ ee->prop.base.h /* base_h */,
+ ee->prop.step.w /* step_x */,
+ ee->prop.step.h /* step_y */,
+ ee->prop.aspect /* min_aspect */,
+ ee->prop.aspect /* max_aspect */);
+}
+
+/* FIXME, should be in idler */
+static void
+_ecore_evas_x_state_update(Ecore_Evas *ee)
+{
+ Ecore_X_Window_State state[10];
+ int num = 0;
+
+ if (ee->prop.modal)
+ state[num++] = ECORE_X_WINDOW_STATE_MODAL;
+ if (ee->prop.sticky)
+ state[num++] = ECORE_X_WINDOW_STATE_STICKY;
+ if (ee->prop.maximized)
+ state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_VERT;
+ if (ee->prop.maximized)
+ state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ;
+// if (bd->client.netwm.state.shaded)
+// state[num++] = ECORE_X_WINDOW_STATE_SHADED;
+ if (ee->prop.focus_skip)
+ state[num++] = ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
+ if (ee->prop.focus_skip)
+ state[num++] = ECORE_X_WINDOW_STATE_SKIP_PAGER;
+// if (bd->client.netwm.state.hidden)
+// state[num++] = ECORE_X_WINDOW_STATE_HIDDEN;
+ if (ee->engine.x.state.fullscreen)
+ state[num++] = ECORE_X_WINDOW_STATE_FULLSCREEN;
+ if (ee->engine.x.state.above)
+ state[num++] = ECORE_X_WINDOW_STATE_ABOVE;
+ if (ee->engine.x.state.below)
+ state[num++] = ECORE_X_WINDOW_STATE_BELOW;
+ if (ee->prop.demand_attention)
+ state[num++] = ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION;
+
+ ecore_x_netwm_window_state_set(ee->prop.window, state, num);
+}
+
+static void
+_ecore_evas_x_layer_update(Ecore_Evas *ee)
+{
+ if (ee->should_be_visible)
+ {
+ /* We need to send a netwm request to the wm */
+ /* FIXME: Do we have to remove old state before adding new? */
+ if (ee->prop.layer < 3)
+ {
+ if (ee->engine.x.state.above)
+ {
+ ee->engine.x.state.above = 0;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_ABOVE, -1, 0);
+ }
+ if (!ee->engine.x.state.below)
+ {
+ ee->engine.x.state.below = 1;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_BELOW, -1, 1);
+ }
+ }
+ else if (ee->prop.layer > 5)
+ {
+ if (ee->engine.x.state.below)
+ {
+ ee->engine.x.state.below = 0;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_BELOW, -1, 0);
+ }
+ if (!ee->engine.x.state.above)
+ {
+ ee->engine.x.state.above = 1;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_ABOVE, -1, 1);
+ }
+ }
+ else
+ {
+ if (ee->engine.x.state.below)
+ {
+ ee->engine.x.state.below = 0;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_BELOW, -1, 0);
+ }
+ if (ee->engine.x.state.above)
+ {
+ ee->engine.x.state.above = 0;
+ ecore_x_netwm_state_request_send(ee->prop.window,
+ ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_ABOVE, -1, 0);
+ }
+ }
+ }
+ else
+ {
+ /* Just set the state */
+ if (ee->prop.layer < 3)
+ {
+ if ((ee->engine.x.state.above) || (!ee->engine.x.state.below))
+ {
+ ee->engine.x.state.above = 0;
+ ee->engine.x.state.below = 1;
+ _ecore_evas_x_state_update(ee);
+ }
+ }
+ else if (ee->prop.layer > 5)
+ {
+ if ((!ee->engine.x.state.above) || (ee->engine.x.state.below))
+ {
+ ee->engine.x.state.above = 1;
+ ee->engine.x.state.below = 0;
+ _ecore_evas_x_state_update(ee);
+ }
+ }
+ else
+ {
+ if ((ee->engine.x.state.above) || (ee->engine.x.state.below))
+ {
+ ee->engine.x.state.above = 0;
+ ee->engine.x.state.below = 0;
+ _ecore_evas_x_state_update(ee);
+ }
+ }
+ }
+ /* FIXME: Set gnome layer */
+}
+
+static int
+_ecore_evas_x_init(void)
+{
+ _ecore_evas_init_count++;
+ if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+ ecore_evas_event_handlers[0] =
+ ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN,
+ _ecore_evas_x_event_mouse_in, NULL);
+ ecore_evas_event_handlers[1] =
+ ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT,
+ _ecore_evas_x_event_mouse_out, NULL);
+ ecore_evas_event_handlers[2] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_IN,
+ _ecore_evas_x_event_window_focus_in, NULL);
+ ecore_evas_event_handlers[3] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT,
+ _ecore_evas_x_event_window_focus_out, NULL);
+ ecore_evas_event_handlers[4] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DAMAGE,
+ _ecore_evas_x_event_window_damage, NULL);
+ ecore_evas_event_handlers[5] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY,
+ _ecore_evas_x_event_window_destroy, NULL);
+ ecore_evas_event_handlers[6] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE,
+ _ecore_evas_x_event_window_configure, NULL);
+ ecore_evas_event_handlers[7] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST,
+ _ecore_evas_x_event_window_delete_request, NULL);
+ ecore_evas_event_handlers[8] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW,
+ _ecore_evas_x_event_window_show, NULL);
+ ecore_evas_event_handlers[9] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE,
+ _ecore_evas_x_event_window_hide, NULL);
+ ecore_evas_event_handlers[10] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY,
+ _ecore_evas_x_event_property_change, NULL);
+ ecore_evas_event_handlers[11] =
+ ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
+ _ecore_evas_x_event_visibility_change, NULL);
+ ecore_evas_event_handlers[12] =
+ ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
+ _ecore_evas_x_event_client_message, NULL);
+ ecore_event_evas_init();
+ return _ecore_evas_init_count;
+}
+
+static void
+_ecore_evas_x_free(Ecore_Evas *ee)
+{
+ _ecore_evas_x_group_leader_unset(ee);
+ _ecore_evas_x_sync_set(ee);
+ if (ee->engine.x.win_shaped_input)
+ ecore_x_window_free(ee->engine.x.win_shaped_input);
+ ecore_x_window_free(ee->prop.window);
+ if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap);
+ if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+ if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc);
+ if (ee->engine.x.damages) ecore_x_xregion_free(ee->engine.x.damages);
+ ee->engine.x.pmap = 0;
+ ee->engine.x.mask = 0;
+ ee->engine.x.gc = 0;
+ ee->engine.x.damages = NULL;
+ ecore_event_window_unregister(ee->prop.window);
+ while (ee->engine.x.win_extra)
+ {
+ Ecore_X_Window *winp;
+
+ winp = ee->engine.x.win_extra->data;
+ ee->engine.x.win_extra =
+ eina_list_remove_list(ee->engine.x.win_extra, ee->engine.x.win_extra);
+ ecore_event_window_unregister(*winp);
+ free(winp);
+ }
+ _ecore_evas_x_shutdown();
+ ecore_x_shutdown();
+}
+
+static void
+_ecore_evas_x_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+ ee->func.fn_delete_request = func;
+ _ecore_evas_x_protocols_set(ee);
+ _ecore_evas_x_sync_set(ee);
+}
+
+static void
+_ecore_evas_x_move(Ecore_Evas *ee, int x, int y)
+{
+ ee->req.x = x;
+ ee->req.y = y;
+ if (ee->engine.x.direct_resize)
+ {
+ if (!ee->engine.x.managed)
+ {
+ if ((x != ee->x) || (y != ee->y))
+ {
+ ee->x = x;
+ ee->y = y;
+ ecore_x_window_move(ee->prop.window, x, y);
+ if (!ee->should_be_visible)
+ {
+ /* We need to request pos */
+ ee->prop.request_pos = 1;
+ _ecore_evas_x_size_pos_hints_update(ee);
+ }
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ }
+ }
+ else
+ {
+ if (((ee->x != x) || (ee->y != y)) ||
+ (ee->engine.x.configure_coming))
+ {
+ ee->engine.x.configure_coming = 1;
+ if (!ee->engine.x.managed)
+ {
+ ee->x = x;
+ ee->y = y;
+ }
+ ecore_x_window_move(ee->prop.window, x, y);
+ }
+ if (!ee->should_be_visible)
+ {
+ /* We need to request pos */
+ ee->prop.request_pos = 1;
+ _ecore_evas_x_size_pos_hints_update(ee);
+ }
+ }
+}
+
+static void
+_ecore_evas_x_managed_move(Ecore_Evas *ee, int x, int y)
+{
+ ee->req.x = x;
+ ee->req.y = y;
+ if (ee->engine.x.direct_resize)
+ {
+ ee->engine.x.managed = 1;
+ if ((x != ee->x) || (y != ee->y))
+ {
+ ee->x = x;
+ ee->y = y;
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ }
+}
+
+static void
+_ecore_evas_x_resize(Ecore_Evas *ee, int w, int h)
+{
+ ee->req.w = w;
+ ee->req.h = h;
+ if (ee->engine.x.direct_resize)
+ {
+ if ((ee->w != w) || (ee->h != h))
+ {
+ ee->w = w;
+ ee->h = h;
+ ecore_x_window_resize(ee->prop.window, w, h);
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+ if ((ee->shaped) || (ee->alpha))
+ _ecore_evas_x_resize_shape(ee);
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ }
+ else if (((ee->w != w) || (ee->h != h)) ||
+ (ee->engine.x.configure_coming))
+ {
+ ee->engine.x.configure_coming = 1;
+ ecore_x_window_resize(ee->prop.window, w, h);
+ }
+}
+
+static void
+_ecore_evas_x_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+ ee->req.x = x;
+ ee->req.y = y;
+ ee->req.w = w;
+ ee->req.h = h;
+ if (ee->engine.x.direct_resize)
+ {
+ if ((ee->w != w) || (ee->h != h) || (x != ee->x) || (y != ee->y))
+ {
+ int change_size = 0, change_pos = 0;
+
+ if ((ee->w != w) || (ee->h != h)) change_size = 1;
+ if (!ee->engine.x.managed)
+ {
+ if ((x != ee->x) || (y != ee->y)) change_pos = 1;
+ }
+ ecore_x_window_move_resize(ee->prop.window, x, y, w, h);
+ if (!ee->engine.x.managed)
+ {
+ ee->x = x;
+ ee->y = y;
+ }
+ ee->w = w;
+ ee->h = h;
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ if (ee->prop.avoid_damage)
+ {
+ int pdam;
+
+ pdam = ecore_evas_avoid_damage_get(ee);
+ ecore_evas_avoid_damage_set(ee, 0);
+ ecore_evas_avoid_damage_set(ee, pdam);
+ }
+ if ((ee->shaped) || (ee->alpha))
+ _ecore_evas_x_resize_shape(ee);
+ if (change_pos)
+ {
+ if (ee->func.fn_move) ee->func.fn_move(ee);
+ }
+ if (change_size)
+ {
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ }
+ }
+ else if (((ee->w != w) || (ee->h != h) || (ee->x != x) || (ee->y != y)) ||
+ (ee->engine.x.configure_coming))
+ {
+ ee->engine.x.configure_coming = 1;
+ ecore_x_window_move_resize(ee->prop.window, x, y, w, h);
+ if (!ee->engine.x.managed)
+ {
+ ee->x = x;
+ ee->y = y;
+ }
+ }
+}
+
+static void
+_ecore_evas_x_rotation_set_internal(Ecore_Evas *ee, int rotation, int resize,
+ Evas_Engine_Info *einfo)
+{
+ int rot_dif;
+
+ rot_dif = ee->rotation - rotation;
+ if (rot_dif < 0) rot_dif = -rot_dif;
+
+ if (rot_dif != 180)
+ {
+ int minw, minh, maxw, maxh, basew, baseh, stepw, steph;
+
+ if (!evas_engine_info_set(ee->evas, einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+
+ if (!resize)
+ {
+ ee->engine.x.configure_coming = 1;
+ if (!ee->prop.fullscreen)
+ {
+ ecore_x_window_resize(ee->prop.window, ee->req.h, ee->req.w);
+ ee->expecting_resize.w = ee->h;
+ ee->expecting_resize.h = ee->w;
+ evas_output_size_set(ee->evas, ee->req.h, ee->req.w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->req.h, ee->req.w);
+ }
+ else
+ {
+ int w, h;
+
+ ecore_x_window_size_get(ee->prop.window, &w, &h);
+ ecore_x_window_resize(ee->prop.window, h, w);
+ if ((rotation == 0) || (rotation == 180))
+ {
+ evas_output_size_set(ee->evas, ee->req.w, ee->req.h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->req.w, ee->req.h);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->req.h, ee->req.w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->req.h, ee->req.w);
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.h, ee->req.w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
+ }
+ else
+ {
+ /* int w, h; */
+
+ /* ecore_x_window_size_get(ee->prop.window, &w, &h); */
+ if ((rotation == 0) || (rotation == 180))
+ {
+ evas_output_size_set(ee->evas, ee->w, ee->h);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ else
+ {
+ evas_output_size_set(ee->evas, ee->h, ee->w);
+ evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w);
+ }
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+ ecore_evas_size_min_get(ee, &minw, &minh);
+ ecore_evas_size_max_get(ee, &maxw, &maxh);
+ ecore_evas_size_base_get(ee, &basew, &baseh);
+ ecore_evas_size_step_get(ee, &stepw, &steph);
+ ee->rotation = rotation;
+ ecore_evas_size_min_set(ee, minh, minw);
+ ecore_evas_size_max_set(ee, maxh, maxw);
+ ecore_evas_size_base_set(ee, baseh, basew);
+ ecore_evas_size_step_set(ee, steph, stepw);
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_x_current_time_get());
+ }
+ else
+ {
+ if (!evas_engine_info_set(ee->evas, einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ ee->rotation = rotation;
+ _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y,
+ ecore_x_current_time_get());
+ if (ee->func.fn_resize) ee->func.fn_resize(ee);
+
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ }
+}
+
+#define _USE_WIN_ROT_EFFECT 1
+
+#if _USE_WIN_ROT_EFFECT
+static void _ecore_evas_x_flush_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED);
+
+typedef struct _Ecore_Evas_X_Rotation_Effect Ecore_Evas_X_Rotation_Effect;
+struct _Ecore_Evas_X_Rotation_Effect
+{
+ Eina_Bool wait_for_comp_reply;
+};
+
+static Ecore_Evas_X_Rotation_Effect _rot_effect =
+{
+ EINA_FALSE
+};
+
+static void
+_ecore_evas_x_rotation_effect_setup(void)
+{
+ _rot_effect.wait_for_comp_reply = EINA_TRUE;
+}
+#endif /* end of _USE_WIN_ROT_EFFECT */
+
+static void
+_ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize)
+{
+ if (ee->rotation == rotation) return;
+ if (!strcmp(ee->driver, "xrender_x11")) return;
+
+#if _USE_WIN_ROT_EFFECT
+ int angles[2];
+ angles[0] = rotation;
+ angles[1] = ee->rotation;
+#endif /* end of _USE_WIN_ROT_EFFECT */
+
+ if (!strcmp(ee->driver, "opengl_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+ Evas_Engine_Info_GL_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+ einfo->info.rotation = rotation;
+ _ecore_evas_x_rotation_set_internal(ee, rotation, resize,
+ (Evas_Engine_Info *)einfo);
+# if _USE_WIN_ROT_EFFECT
+ ecore_x_window_prop_property_set(ee->prop.window,
+ ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+ ECORE_X_ATOM_CARDINAL, 32, &angles, 2);
+# else
+ ecore_x_window_prop_property_set(ee->prop.window,
+ ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+ ECORE_X_ATOM_CARDINAL, 32, &rotation, 1);
+# endif
+#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */
+ }
+ else if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+ einfo->info.rotation = rotation;
+ _ecore_evas_x_rotation_set_internal(ee, rotation, resize,
+ (Evas_Engine_Info *)einfo);
+# if _USE_WIN_ROT_EFFECT
+ ecore_x_window_prop_property_set(ee->prop.window,
+ ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+ ECORE_X_ATOM_CARDINAL, 32, &angles, 2);
+# else
+ ecore_x_window_prop_property_set(ee->prop.window,
+ ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+ ECORE_X_ATOM_CARDINAL, 32, &rotation, 1);
+# endif
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
+ }
+
+#if _USE_WIN_ROT_EFFECT
+ if ((ee->visible) &&
+ ((ecore_x_e_comp_sync_supported_get(ee->engine.x.win_root)) &&
+ (!ee->no_comp_sync) && (_ecore_evas_app_comp_sync)) &&
+ (ee->engine.x.sync_counter) &&
+ (ee->engine.x.sync_val > 0))
+ {
+ _ecore_evas_x_rotation_effect_setup();
+ _ecore_evas_x_flush_pre(ee, NULL, NULL);
+ }
+#endif /* end of _USE_WIN_ROT_EFFECT */
+}
+
+static void
+_ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
+{
+ if ((ee->shaped == shaped)) return;
+ if (!strcmp(ee->driver, "opengl_x11")) return;
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ ee->shaped = shaped;
+ if (einfo)
+ {
+ if (ee->shaped)
+ {
+ unsigned int foreground;
+ Ecore_X_GC gc;
+
+ if (!ee->engine.x.mask)
+ ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1);
+ foreground = 0;
+ gc = ecore_x_gc_new(ee->engine.x.mask,
+ ECORE_X_GC_VALUE_MASK_FOREGROUND,
+ &foreground);
+ ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc,
+ 0, 0, ee->w, ee->h);
+ ecore_x_gc_free(gc);
+ einfo->info.mask = ee->engine.x.mask;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
+ }
+ else
+ {
+ if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+ ee->engine.x.mask = 0;
+ einfo->info.mask = 0;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ ecore_x_window_shape_mask_set(ee->prop.window, 0);
+ ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
+ }
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
+ }
+}
+
+/* FIXME, round trip */
+static void
+_ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
+{
+ Ecore_X_Window_Attributes att;
+ char *id = NULL;
+
+ if ((ee->alpha == alpha)) return;
+
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+
+ if (!ecore_x_composite_query()) return;
+
+ ee->shaped = 0;
+ ee->alpha = alpha;
+ ecore_x_window_free(ee->prop.window);
+ ecore_event_window_unregister(ee->prop.window);
+ if (ee->alpha)
+ {
+ if (ee->prop.override)
+ ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ else
+ ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+// if (!ee->engine.x.mask)
+// ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1);
+ }
+ else
+ {
+ if (ee->prop.override)
+ ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ else
+ ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+ ee->engine.x.mask = 0;
+ ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
+ }
+
+ einfo->info.destination_alpha = alpha;
+
+ ecore_x_window_attributes_get(ee->prop.window, &att);
+ einfo->info.visual = att.visual;
+ einfo->info.colormap = att.colormap;
+ einfo->info.depth = att.depth;
+
+// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+// ee->engine.x.mask = 0;
+ einfo->info.mask = ee->engine.x.mask;
+ einfo->info.drawable = ee->prop.window;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
+ ecore_x_window_shape_mask_set(ee->prop.window, 0);
+ ecore_x_input_multi_select(ee->prop.window);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+ if (ee->prop.borderless)
+ ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
+ if (ee->visible) ecore_x_window_show(ee->prop.window);
+ if (ee->prop.focused) ecore_x_window_focus(ee->prop.window);
+ if (ee->prop.title)
+ {
+ ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
+ ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
+ }
+ if (ee->prop.name)
+ ecore_x_icccm_name_class_set(ee->prop.window,
+ ee->prop.name, ee->prop.clas);
+ _ecore_evas_x_hints_update(ee);
+ _ecore_evas_x_group_leader_update(ee);
+ ecore_x_window_defaults_set(ee->prop.window);
+ _ecore_evas_x_protocols_set(ee);
+ _ecore_evas_x_sync_set(ee);
+ _ecore_evas_x_size_pos_hints_update(ee);
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
+ if ((id = getenv("DESKTOP_STARTUP_ID")))
+ {
+ ecore_x_netwm_startup_id_set(ee->prop.window, id);
+ /* NB: on linux this may simply empty the env as opposed to completely
+ * unset it to being empty - unsure as solartis libc crashes looking
+ * for the '=' char */
+ // putenv((char*)"DESKTOP_STARTUP_ID=");
+ }
+ }
+ else if (!strcmp(ee->driver, "opengl_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+ Evas_Engine_Info_GL_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+
+ if (!ecore_x_composite_query()) return;
+
+ ee->shaped = 0;
+ ee->alpha = alpha;
+ ecore_x_window_free(ee->prop.window);
+ ecore_event_window_unregister(ee->prop.window);
+ ee->prop.window = 0;
+
+ einfo->info.destination_alpha = alpha;
+
+ if (ee->engine.x.win_root != 0)
+ {
+ /* FIXME: round trip in ecore_x_window_argb_get */
+ if (ecore_x_window_argb_get(ee->engine.x.win_root))
+ {
+ ee->prop.window =
+ _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root,
+ ee->req.x, ee->req.y,
+ ee->req.w, ee->req.h,
+ ee->prop.override, 1, NULL);
+ }
+ else
+ {
+ ee->prop.window =
+ _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root,
+ ee->req.x, ee->req.y,
+ ee->req.w, ee->req.h,
+ ee->prop.override, ee->alpha,
+ NULL);
+ }
+ }
+ else
+ {
+ ee->prop.window =
+ _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root,
+ ee->req.x, ee->req.y,
+ ee->req.w, ee->req.h,
+ ee->prop.override, ee->alpha, NULL);
+ }
+
+ if (!ee->prop.window) return;
+/*
+ if (ee->alpha)
+ {
+ if (ee->prop.override)
+ ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ else
+ ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ if (!ee->engine.x.mask)
+ ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1);
+ }
+ else
+ {
+ if (ee->prop.override)
+ ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ else
+ ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
+ if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+ ee->engine.x.mask = 0;
+ ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
+ }
+ */
+
+ ecore_x_window_attributes_get(ee->prop.window, &att);
+ einfo->info.visual = att.visual;
+ einfo->info.colormap = att.colormap;
+ einfo->info.depth = att.depth;
+
+// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask);
+// ee->engine.x.mask = 0;
+// einfo->info.mask = ee->engine.x.mask;
+ einfo->info.drawable = ee->prop.window;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
+// ecore_x_window_shape_mask_set(ee->prop.window, 0);
+ ecore_x_input_multi_select(ee->prop.window);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+ if (ee->prop.borderless)
+ ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
+ if (ee->visible) ecore_x_window_show(ee->prop.window);
+ if (ee->prop.focused) ecore_x_window_focus(ee->prop.window);
+ if (ee->prop.title)
+ {
+ ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
+ ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
+ }
+ if (ee->prop.name)
+ ecore_x_icccm_name_class_set(ee->prop.window,
+ ee->prop.name, ee->prop.clas);
+ _ecore_evas_x_hints_update(ee);
+ _ecore_evas_x_group_leader_update(ee);
+ ecore_x_window_defaults_set(ee->prop.window);
+ _ecore_evas_x_protocols_set(ee);
+ _ecore_evas_x_sync_set(ee);
+ _ecore_evas_x_size_pos_hints_update(ee);
+#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */
+ if ((id = getenv("DESKTOP_STARTUP_ID")))
+ {
+ ecore_x_netwm_startup_id_set(ee->prop.window, id);
+ /* NB: on linux this may simply empty the env as opposed to completely
+ * unset it to being empty - unsure as solartis libc crashes looking
+ * for the '=' char */
+ // putenv((char*)"DESKTOP_STARTUP_ID=");
+ }
+ }
+}
+
+static void
+_ecore_evas_x_transparent_set(Ecore_Evas *ee, int transparent)
+{
+ if ((ee->transparent == transparent)) return;
+
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (!einfo) return;
+
+ ee->transparent = transparent;
+ einfo->info.destination_alpha = transparent;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+#endif
+ }
+}
+
+static void
+_ecore_evas_x_window_group_set(Ecore_Evas *ee, const Ecore_Evas *group_ee)
+{
+ if (ee->prop.group_ee == group_ee) return;
+
+ ee->prop.group_ee = (Ecore_Evas *)group_ee;
+ if (ee->prop.group_ee)
+ ee->prop.group_ee_win = group_ee->prop.window;
+ else
+ ee->prop.group_ee_win = 0;
+ _ecore_evas_x_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect)
+{
+ if (ee->prop.aspect == aspect) return;
+
+ ee->prop.aspect = aspect;
+ _ecore_evas_x_size_pos_hints_update(ee);
+// netwm state
+// if (ee->should_be_visible)
+// ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+// ECORE_X_WINDOW_STATE_STICKY, -1, sticky);
+// else
+// _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_urgent_set(Ecore_Evas *ee, int urgent)
+{
+ if (ee->prop.urgent == urgent) return;
+
+ ee->prop.urgent = urgent;
+ _ecore_evas_x_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_modal_set(Ecore_Evas *ee, int modal)
+{
+ if (ee->prop.modal == modal) return;
+
+ ee->prop.modal = modal;
+ if (ee->should_be_visible)
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_MODAL, -1, modal);
+ else
+ _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_demand_attention_set(Ecore_Evas *ee, int demand)
+{
+ if (ee->prop.demand_attention == demand) return;
+
+ ee->prop.demand_attention = demand;
+ if (ee->should_be_visible)
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION, -1, demand);
+ else
+ _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_focus_skip_set(Ecore_Evas *ee, int skip)
+{
+ if (ee->prop.focus_skip == skip) return;
+
+ ee->prop.focus_skip = skip;
+ if (ee->should_be_visible)
+ {
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_SKIP_TASKBAR, -1, skip);
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_SKIP_PAGER, -1, skip);
+ }
+ else
+ _ecore_evas_x_state_update(ee);
+ _ecore_evas_x_hints_update(ee);
+}
+
+#endif /* BUILD_ECORE_EVAS_X11 */
+
+#ifdef BUILD_ECORE_EVAS_X11
+static void
+_ecore_evas_x_show(Ecore_Evas *ee)
+{
+ ee->should_be_visible = 1;
+ if (ee->prop.avoid_damage)
+ _ecore_evas_x_render(ee);
+ _ecore_evas_x_sync_set(ee);
+ ecore_x_window_show(ee->prop.window);
+ if (ee->prop.fullscreen)
+ ecore_x_window_focus(ee->prop.window);
+}
+
+static void
+_ecore_evas_x_hide(Ecore_Evas *ee)
+{
+ ecore_x_window_hide(ee->prop.window);
+ ee->should_be_visible = 0;
+ _ecore_evas_x_sync_set(ee);
+}
+
+static void
+_ecore_evas_x_raise(Ecore_Evas *ee)
+{
+ ecore_x_window_raise(ee->prop.window);
+}
+
+static void
+_ecore_evas_x_lower(Ecore_Evas *ee)
+{
+ ecore_x_window_lower(ee->prop.window);
+}
+
+static void
+_ecore_evas_x_activate(Ecore_Evas *ee)
+{
+ ecore_x_netwm_client_active_request(ee->engine.x.win_root,
+ ee->prop.window, 2, 0);
+}
+
+static void
+_ecore_evas_x_title_set(Ecore_Evas *ee, const char *t)
+{
+ if (ee->prop.title) free(ee->prop.title);
+ ee->prop.title = NULL;
+ if (t) ee->prop.title = strdup(t);
+ ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
+ ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
+}
+
+static void
+_ecore_evas_x_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
+{
+ if (ee->prop.name) free(ee->prop.name);
+ if (ee->prop.clas) free(ee->prop.clas);
+ ee->prop.name = NULL;
+ ee->prop.clas = NULL;
+ if (n) ee->prop.name = strdup(n);
+ if (c) ee->prop.clas = strdup(c);
+ ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas);
+}
+
+static void
+_ecore_evas_x_size_min_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return;
+ ee->prop.min.w = w;
+ ee->prop.min.h = h;
+ _ecore_evas_x_size_pos_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_size_max_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return;
+ ee->prop.max.w = w;
+ ee->prop.max.h = h;
+ _ecore_evas_x_size_pos_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_size_base_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+ if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return;
+ ee->prop.base.w = w;
+ ee->prop.base.h = h;
+ _ecore_evas_x_size_pos_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_size_step_set(Ecore_Evas *ee, int w, int h)
+{
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return;
+ ee->prop.step.w = w;
+ ee->prop.step.h = h;
+ _ecore_evas_x_size_pos_hints_update(ee);
+}
+
+static void
+_ecore_evas_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee;
+
+ ee = data;
+ if (ee) ee->prop.cursor.object = NULL;
+}
+
+static void
+_ecore_evas_x_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+{
+ int x, y;
+
+ if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object);
+
+ if (!obj)
+ {
+ ee->prop.cursor.object = NULL;
+ ee->prop.cursor.layer = 0;
+ ee->prop.cursor.hot.x = 0;
+ ee->prop.cursor.hot.y = 0;
+ ecore_x_window_cursor_show(ee->prop.window, 1);
+ return;
+ }
+
+ ee->prop.cursor.object = obj;
+ ee->prop.cursor.layer = layer;
+ ee->prop.cursor.hot.x = hot_x;
+ ee->prop.cursor.hot.y = hot_y;
+
+ ecore_x_window_cursor_show(ee->prop.window, 0);
+
+ evas_pointer_output_xy_get(ee->evas, &x, &y);
+ evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer);
+ evas_object_move(ee->prop.cursor.object,
+ x - ee->prop.cursor.hot.x,
+ y - ee->prop.cursor.hot.y);
+ evas_object_pass_events_set(ee->prop.cursor.object, 1);
+ if (evas_pointer_inside_get(ee->evas))
+ evas_object_show(ee->prop.cursor.object);
+
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee);
+}
+
+/*
+ * @param ee
+ * @param layer If < 3, @a ee will be put below all other windows.
+ * If > 5, @a ee will be "always-on-top"
+ * If = 4, @a ee will be put in the default layer.
+ * Acceptable values range from 1 to 255 (0 reserved for
+ * desktop windows)
+ */
+static void
+_ecore_evas_x_layer_set(Ecore_Evas *ee, int layer)
+{
+ if (ee->prop.layer == layer) return;
+
+ /* FIXME: Should this logic be here? */
+ if (layer < 1)
+ layer = 1;
+ else if (layer > 255)
+ layer = 255;
+
+ ee->prop.layer = layer;
+ _ecore_evas_x_layer_update(ee);
+}
+
+static void
+_ecore_evas_x_focus_set(Ecore_Evas *ee, int on EINA_UNUSED)
+{
+ ecore_x_window_focus(ee->prop.window);
+}
+
+static void
+_ecore_evas_x_iconified_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.iconified == on) return;
+ ee->prop.iconified = on;
+ _ecore_evas_x_hints_update(ee);
+ if (on)
+ ecore_x_icccm_iconic_request_send(ee->prop.window, ee->engine.x.win_root);
+ else
+ ecore_evas_show(ee);
+}
+
+static void
+_ecore_evas_x_borderless_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.borderless == on) return;
+ ee->prop.borderless = on;
+ ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
+}
+
+/* FIXME: This function changes the initial state of the ee
+ * whilest the iconic function changes the current state! */
+static void
+_ecore_evas_x_withdrawn_set(Ecore_Evas *ee, int withdrawn)
+{
+ if (ee->prop.withdrawn == withdrawn) return;
+ ee->prop.withdrawn = withdrawn;
+ _ecore_evas_x_hints_update(ee);
+}
+
+static void
+_ecore_evas_x_sticky_set(Ecore_Evas *ee, int sticky)
+{
+ if (ee->prop.sticky == sticky) return;
+
+ /* We dont want to set prop.sticky here as it will cause
+ * the sticky callback not to get called. Its set on the
+ * property change event.
+ * ee->prop.sticky = sticky;
+ */
+ ee->engine.x.state.sticky = sticky;
+ if (ee->should_be_visible)
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_STICKY, -1, sticky);
+ else
+ _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_ignore_events_set(Ecore_Evas *ee, int ignore)
+{
+ if (ee->ignore_events == ignore) return;
+
+ ee->ignore_events = ignore;
+ if (ee->prop.window)
+ ecore_x_window_ignore_set(ee->prop.window, ignore);
+}
+
+/*
+static void
+_ecore_evas_x_reinit_win(Ecore_Evas *ee)
+{
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.drawable = ee->prop.window;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ }
+#endif
+ }
+ else if (!strcmp(ee->driver, "opengl_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+ Evas_Engine_Info_GL_X11 *einfo;
+
+ einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->info.drawable = ee->prop.window;
+ evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo);
+ }
+#endif
+ }
+}
+*/
+
+static void
+_ecore_evas_x_override_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.override == on) return;
+ if (ee->should_be_visible) ecore_x_window_hide(ee->prop.window);
+ ecore_x_window_override_set(ee->prop.window, on);
+ if (ee->should_be_visible) ecore_x_window_show(ee->prop.window);
+ if (ee->prop.focused) ecore_x_window_focus(ee->prop.window);
+ ee->prop.override = on;
+}
+
+static void
+_ecore_evas_x_maximized_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.maximized == on) return;
+ ee->engine.x.state.maximized_h = 1;
+ ee->engine.x.state.maximized_v = 1;
+ ee->prop.maximized = on;
+ if (ee->should_be_visible)
+ {
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, -1, on);
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, -1, on);
+ }
+ else
+ _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_fullscreen_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.fullscreen == on) return;
+
+ /* FIXME: Detect if WM is EWMH compliant and handle properly if not,
+ * i.e. reposition, resize, and change borderless hint */
+ ee->engine.x.state.fullscreen = on;
+ if (ee->should_be_visible)
+ ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
+ ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on);
+ else
+ _ecore_evas_x_state_update(ee);
+}
+
+static void
+_ecore_evas_x_profiles_set(Ecore_Evas *ee, const char **plist, int n)
+{
+ /* Ecore_Evas's profile will be updated when WM sets the E_PROFILE. */
+ ecore_x_e_window_profile_list_set(ee->prop.window, plist, n);
+}
+
+static void
+_ecore_evas_x_avoid_damage_set(Ecore_Evas *ee, int on)
+{
+ if (ee->prop.avoid_damage == on) return;
+ if (!strcmp(ee->driver, "opengl_x11")) return;
+
+ if (!strcmp(ee->driver, "software_x11"))
+ {
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+ Evas_Engine_Info_Software_X11 *einfo;
+
+ ee->prop.avoid_damage = on;
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ if (ee->prop.avoid_damage)
+ {
+ ee->engine.x.pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, einfo->info.depth);
+ ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap, 0, NULL);
+ einfo->info.drawable = ee->engine.x.pmap;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ if ((ee->rotation == 90) || (ee->rotation == 270))
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
+ else
+ evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+ if (ee->prop.avoid_damage == ECORE_EVAS_AVOID_DAMAGE_BUILT_IN)
+ {
+ ee->engine.x.using_bg_pixmap = 1;
+ ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap);
+ ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
+ }
+ if (ee->engine.x.direct_resize)
+ {
+ /* Turn this off for now
+ ee->engine.x.using_bg_pixmap = 1;
+ ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap);
+ */
+ }
+ }
+ else
+ {
+ if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap);
+ if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc);
+ if (ee->engine.x.using_bg_pixmap)
+ {
+ ecore_x_window_pixmap_set(ee->prop.window, 0);
+ ee->engine.x.using_bg_pixmap = 0;
+ ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
+ }
+ ee->engine.x.pmap = 0;
+ ee->engine.x.gc = 0;
+ einfo->info.drawable = ee->prop.window;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+ }
+#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
+ }
+}
+
+static void
+_ecore_evas_x_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h)
+{
+ int outnum = 0;
+ int px = 0, py = 0, pw = 0, ph = 0;
+ Ecore_X_Window root;
+ Ecore_X_Randr_Output *out = NULL;
+ Ecore_X_Randr_Crtc crtc;
+ unsigned int val[4] = { 0 };
+
+ if (ecore_x_window_prop_card32_get
+ (ee->prop.window, ecore_x_atom_get("E_ZONE_GEOMETRY"), val, 4) == 4)
+ {
+ if (x) *x = (int)val[0];
+ if (y) *y = (int)val[1];
+ if (w) *w = (int)val[2];
+ if (h) *h = (int)val[3];
+ return;
+ }
+
+ root = ecore_x_window_root_get(ee->prop.window);
+ out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum);
+ if (!out)
+ {
+norandr:
+ if (out) free(out);
+ if (x) *x = 0;
+ if (y) *y = 0;
+ ecore_x_window_size_get(root, w, h);
+ return;
+ }
+ crtc = ecore_x_randr_output_crtc_get(root, out[0]);
+ if (!crtc) goto norandr;
+ ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &pw, &ph);
+ if ((pw == 0) || (ph == 0)) goto norandr;
+ if (x) *x = px;
+ if (y) *y = py;
+ if (w) *w = pw;
+ if (h) *h = ph;
+ free(out);
+}
+
+static void
+_ecore_evas_x_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi)
+{
+ int scdpi, xmm = 0, ymm = 0, outnum = 0, w = 0, h = 0;
+ int px = 0, py = 0;
+ Ecore_X_Window root;
+ Ecore_X_Randr_Output *out = NULL;
+ Ecore_X_Randr_Crtc crtc;
+
+ root = ecore_x_window_root_get(ee->prop.window);
+ out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum);
+ if (!out)
+ {
+norandr:
+ if (out) free(out);
+ scdpi = ecore_x_dpi_get();
+ if (xdpi) *xdpi = scdpi;
+ if (ydpi) *ydpi = scdpi;
+ return;
+ }
+ crtc = ecore_x_randr_output_crtc_get(root, out[0]);
+ if (!crtc) goto norandr;
+ ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &w, &h);
+ if ((w == 0) || (h == 0)) goto norandr;
+ ecore_x_randr_output_size_mm_get(root, out[0], &xmm, &ymm);
+ if ((xmm == 0) || (ymm == 0)) goto norandr;
+ if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch
+ if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch
+ free(out);
+}
+
+int
+_ecore_evas_x_shutdown(void)
+{
+ _ecore_evas_init_count--;
+ if (_ecore_evas_init_count == 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < sizeof(ecore_evas_event_handlers) / sizeof(Ecore_Event_Handler*); i++)
+ {
+ if (ecore_evas_event_handlers[i])
+ ecore_event_handler_del(ecore_evas_event_handlers[i]);
+ }
+ ecore_event_evas_shutdown();
+ }
+ if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
+ return _ecore_evas_init_count;
+}
+
+static Ecore_Evas_Engine_Func _ecore_x_engine_func =
+{
+ _ecore_evas_x_free,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_x_callback_delete_request_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ _ecore_evas_x_move,
+ _ecore_evas_x_managed_move,
+ _ecore_evas_x_resize,
+ _ecore_evas_x_move_resize,
+ _ecore_evas_x_rotation_set,
+ _ecore_evas_x_shaped_set,
+ _ecore_evas_x_show,
+ _ecore_evas_x_hide,
+ _ecore_evas_x_raise,
+ _ecore_evas_x_lower,
+ _ecore_evas_x_activate,
+ _ecore_evas_x_title_set,
+ _ecore_evas_x_name_class_set,
+ _ecore_evas_x_size_min_set,
+ _ecore_evas_x_size_max_set,
+ _ecore_evas_x_size_base_set,
+ _ecore_evas_x_size_step_set,
+ _ecore_evas_x_object_cursor_set,
+ _ecore_evas_x_layer_set,
+ _ecore_evas_x_focus_set,
+ _ecore_evas_x_iconified_set,
+ _ecore_evas_x_borderless_set,
+ _ecore_evas_x_override_set,
+ _ecore_evas_x_maximized_set,
+ _ecore_evas_x_fullscreen_set,
+ _ecore_evas_x_avoid_damage_set,
+ _ecore_evas_x_withdrawn_set,
+ _ecore_evas_x_sticky_set,
+ _ecore_evas_x_ignore_events_set,
+ _ecore_evas_x_alpha_set,
+ _ecore_evas_x_transparent_set,
+ _ecore_evas_x_profiles_set,
+
+ _ecore_evas_x_window_group_set,
+ _ecore_evas_x_aspect_set,
+ _ecore_evas_x_urgent_set,
+ _ecore_evas_x_modal_set,
+ _ecore_evas_x_demand_attention_set,
+ _ecore_evas_x_focus_skip_set,
+
+ NULL, // render
+ _ecore_evas_x_screen_geometry_get,
+ _ecore_evas_x_screen_dpi_get
+};
+#endif /* BUILD_ECORE_EVAS_X11 */
+
+/*
+ * FIXME: there are some round trips. Especially, we can split
+ * ecore_x_init in 2 functions and suppress some round trips.
+ */
+
+#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_OPENGL_X11)
+static void
+_ecore_evas_x_flush_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+
+ if (ee->no_comp_sync) return;
+ if (!_ecore_evas_app_comp_sync) return;
+ if (ee->engine.x.sync_counter)
+ {
+ if (ee->engine.x.sync_began)
+ {
+ ee->engine.x.sync_val++;
+ if (!ee->engine.x.sync_cancel)
+ {
+ if (!ee->semi_sync)
+ ecore_x_sync_counter_val_wait(ee->engine.x.sync_counter,
+ ee->engine.x.sync_val);
+ }
+ }
+ }
+}
+
+static void
+_ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Ecore_Evas *ee = data;
+
+ if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) &&
+ (!ee->gl_sync_draw_done)) // added by gl77.lee
+ {
+ if (ee->engine.x.sync_counter)
+ {
+ if (ee->engine.x.sync_began)
+ {
+ if (!ee->engine.x.sync_cancel)
+ {
+ ecore_x_e_comp_sync_draw_size_done_send
+ (ee->engine.x.win_root, ee->prop.window, ee->w, ee->h);
+ }
+ }
+ }
+ }
+ if (ee->engine.x.netwm_sync_set)
+ {
+ ecore_x_sync_counter_2_set(ee->engine.x.netwm_sync_counter,
+ ee->engine.x.netwm_sync_val_hi,
+ ee->engine.x.netwm_sync_val_lo);
+ ee->engine.x.netwm_sync_set = 0;
+ }
+}
+#endif
+
+/**
+ * @brief Create Ecore_Evas using software x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned.
+ * @param disp_name The name of the Ecore_Evas to be created.
+ * @param parent The parent of the Ecore_Evas to be created.
+ * @param x The X coordinate to be used.
+ * @param y The Y coordinate to be used.
+ * @param w The width of the Ecore_Evas to be created.
+ * @param h The height of the Ecore_Evas to be created.
+ * @return A handle to the created Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+EAPI Ecore_Evas *
+ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent,
+ int x, int y, int w, int h)
+{
+ Evas_Engine_Info_Software_X11 *einfo;
+ Ecore_Evas *ee;
+ int argb = 0, rmethod;
+ static int redraw_debug = -1;
+ char *id = NULL;
+
+ rmethod = evas_render_method_lookup("software_x11");
+ if (!rmethod) return NULL;
+ if (!ecore_x_init(disp_name)) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ _ecore_evas_x_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
+
+ ee->driver = "software_x11";
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->engine.x.state.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE,
+ _ecore_evas_x_flush_pre, ee);
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST,
+ _ecore_evas_x_flush_post, ee);
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ ee->engine.x.win_root = parent;
+ ee->engine.x.screen_num = 0;
+
+ if (parent != 0)
+ {
+ ee->engine.x.screen_num = 1; /* FIXME: get real scren # */
+ /* FIXME: round trip in ecore_x_window_argb_get */
+ if (ecore_x_window_argb_get(parent))
+ {
+ ee->prop.window = ecore_x_window_argb_new(parent, x, y, w, h);
+ argb = 1;
+ }
+ else
+ ee->prop.window = ecore_x_window_new(parent, x, y, w, h);
+ }
+ else
+ ee->prop.window = ecore_x_window_new(parent, x, y, w, h);
+ if ((id = getenv("DESKTOP_STARTUP_ID")))
+ {
+ ecore_x_netwm_startup_id_set(ee->prop.window, id);
+ /* NB: on linux this may simply empty the env as opposed to completely
+ * unset it to being empty - unsure as solartis libc crashes looking
+ * for the '=' char */
+// putenv((char*)"DESKTOP_STARTUP_ID=");
+ }
+ einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ Ecore_X_Screen *screen;
+
+ /* FIXME: this is inefficient as its 1 or more round trips */
+ screen = ecore_x_default_screen_get();
+ if (ecore_x_screen_count_get() > 1)
+ {
+ Ecore_X_Window *roots;
+ int num, i;
+
+ num = 0;
+ roots = ecore_x_window_root_list(&num);
+ if (roots)
+ {
+ Ecore_X_Window root;
+
+ root = ecore_x_window_root_get(parent);
+ for (i = 0; i < num; i++)
+ {
+ if (root == roots[i])
+ {
+ screen = ecore_x_screen_get(i);
+ break;
+ }
+ }
+ free(roots);
+ }
+ }
+
+ einfo->info.destination_alpha = argb;
+
+ if (redraw_debug < 0)
+ {
+ if (getenv("REDRAW_DEBUG"))
+ redraw_debug = atoi(getenv("REDRAW_DEBUG"));
+ else
+ redraw_debug = 0;
+ }
+
+# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB
+ einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XCB;
+ einfo->info.connection = ecore_x_connection_get();
+ einfo->info.screen = screen;
+# else
+ einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB;
+ einfo->info.connection = ecore_x_display_get();
+ einfo->info.screen = NULL;
+# endif
+ einfo->info.drawable = ee->prop.window;
+
+ if (argb)
+ {
+ Ecore_X_Window_Attributes at;
+
+ ecore_x_window_attributes_get(ee->prop.window, &at);
+ einfo->info.visual = at.visual;
+ einfo->info.colormap = at.colormap;
+ einfo->info.depth = at.depth;
+ einfo->info.destination_alpha = 1;
+ }
+ else
+ {
+ einfo->info.visual =
+ ecore_x_default_visual_get(einfo->info.connection, screen);
+ einfo->info.colormap =
+ ecore_x_default_colormap_get(einfo->info.connection, screen);
+ einfo->info.depth =
+ ecore_x_default_depth_get(einfo->info.connection, screen);
+ einfo->info.destination_alpha = 0;
+ }
+
+ einfo->info.rotation = 0;
+ einfo->info.debug = redraw_debug;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ }
+
+ _ecore_evas_x_hints_update(ee);
+ _ecore_evas_x_group_leader_set(ee);
+ ecore_x_window_defaults_set(ee->prop.window);
+ _ecore_evas_x_protocols_set(ee);
+ _ecore_evas_x_sync_set(ee);
+
+ ee->engine.func->fn_render = _ecore_evas_x_render;
+ _ecore_evas_register(ee);
+ ecore_x_input_multi_select(ee->prop.window);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+ return ee;
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_software_x11_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED,
+ int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * @brief Get the window from Ecore_Evas using software x11.
+ * @note If ecore is not compiled with support for x11 or if @p ee was not
+ * created with ecore_evas_software_x11_new() then nothing is done and
+ * 0 is returned.
+ * @param ee The Ecore_Evas from which to get the window.
+ * @return The window of type Ecore_X_Window.
+ */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+EAPI Ecore_X_Window
+ecore_evas_software_x11_window_get(const Ecore_Evas *ee)
+{
+ if (!(!strcmp(ee->driver, "software_x11"))) return 0;
+ return (Ecore_X_Window) ecore_evas_window_get(ee);
+}
+#else
+EAPI Ecore_X_Window
+ecore_evas_software_x11_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+#endif
+
+/**
+ * @brief Set the direct_resize of Ecore_Evas using software x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done.
+ * @param ee The Ecore_Evas in which to set direct resize.
+ * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE.
+ */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+EAPI void
+ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ ee->engine.x.direct_resize = on;
+ if (ee->prop.avoid_damage)
+ {
+ if (ee->engine.x.direct_resize)
+ {
+/* turn this off for now
+ ee->engine.x.using_bg_pixmap = 1;
+ ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap);
+ */
+ }
+ else
+ {
+/* turn this off too- bg pixmap is controlled by avoid damage directly
+ ee->engine.x.using_bg_pixmap = 0;
+ ecore_x_window_pixmap_set(ee->prop.window, 0);
+ ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
+ */
+ }
+ }
+}
+#else
+EAPI void
+ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee EINA_UNUSED, Eina_Bool on EINA_UNUSED)
+{
+}
+#endif
+
+/**
+ * @brief Gets if the Ecore_Evas is being directly resized using software x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done and EINA_FALSE is returned.
+ * @param ee The Ecore_Evas from which to get direct resize.
+ * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE.
+ */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+EAPI Eina_Bool
+ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee)
+{
+ return ee->engine.x.direct_resize;
+}
+#else
+EAPI Eina_Bool
+ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+#endif
+
+/**
+ * @brief Add extra window on Ecore_Evas using software x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done.
+ * @param ee The Ecore_Evas on which to add the window.
+ * @param win The window to be added at the Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
+EAPI void
+ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win)
+{
+ Ecore_X_Window *winp;
+
+ winp = malloc(sizeof(Ecore_X_Window));
+ if (winp)
+ {
+ *winp = win;
+ ee->engine.x.win_extra = eina_list_append(ee->engine.x.win_extra, winp);
+ ecore_x_input_multi_select(win);
+ ecore_event_window_register(win, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+ }
+}
+#else
+EAPI void
+ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee EINA_UNUSED, Ecore_X_Window win EINA_UNUSED)
+{
+}
+#endif
+
+/**
+ * @brief Create Ecore_Evas using opengl x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned.
+ * @param disp_name The name of the display of the Ecore_Evas to be created.
+ * @param parent The parent of the Ecore_Evas to be created.
+ * @param x The X coordinate to be used.
+ * @param y The Y coordinate to be used.
+ * @param w The width of the Ecore_Evas to be created.
+ * @param h The height of the Ecore_Evas to be created.
+ * @return The new Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI Ecore_Evas *
+ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent,
+ int x, int y, int w, int h)
+{
+ return ecore_evas_gl_x11_options_new(disp_name, parent, x, y, w, h, NULL);
+}
+
+EAPI Ecore_Evas *
+ecore_evas_gl_x11_options_new(const char *disp_name, Ecore_X_Window parent,
+ int x, int y, int w, int h, const int *opt)
+{
+ Ecore_Evas *ee;
+ int rmethod;
+ char *id = NULL;
+
+ rmethod = evas_render_method_lookup("gl_x11");
+ if (!rmethod) return NULL;
+ if (!ecore_x_init(disp_name)) return NULL;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->gl_sync_draw_done = -1; // added by gl77.lee
+
+ _ecore_evas_x_init();
+
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
+
+ ee->driver = "opengl_x11";
+#if 1
+ ee->semi_sync = 0; // gl engine doesn't need to sync - its whole swaps
+#else
+ if (!getenv("ECORE_EVAS_COMP_NOSEMISYNC"))
+ ee->semi_sync = 1; // gl engine doesn't need to sync - its whole swaps
+// ee->no_comp_sync = 1; // gl engine doesn't need to sync - its whole swaps
+#endif
+ if (disp_name) ee->name = strdup(disp_name);
+
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+ ee->x = x;
+ ee->y = y;
+ ee->w = w;
+ ee->h = h;
+ ee->req.x = ee->x;
+ ee->req.y = ee->y;
+ ee->req.w = ee->w;
+ ee->req.h = ee->h;
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->engine.x.state.sticky = 0;
+
+ /* init evas here */
+ ee->evas = evas_new();
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, _ecore_evas_x_flush_pre, ee);
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, _ecore_evas_x_flush_post, ee);
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, rmethod);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ if (parent == 0) parent = DefaultRootWindow(ecore_x_display_get());
+ ee->engine.x.win_root = parent;
+
+ if (ee->engine.x.win_root != 0)
+ {
+ ee->engine.x.screen_num = 1; /* FIXME: get real scren # */
+ /* FIXME: round trip in ecore_x_window_argb_get */
+ if (ecore_x_window_argb_get(ee->engine.x.win_root))
+ {
+ ee->prop.window = _ecore_evas_x_gl_window_new
+ (ee, ee->engine.x.win_root, x, y, w, h, 0, 1, opt);
+ }
+ else
+ ee->prop.window = _ecore_evas_x_gl_window_new
+ (ee, ee->engine.x.win_root, x, y, w, h, 0, 0, opt);
+ }
+ else
+ ee->prop.window = _ecore_evas_x_gl_window_new
+ (ee, ee->engine.x.win_root, x, y, w, h, 0, 0, opt);
+ if (!ee->prop.window)
+ {
+ ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
+ ecore_evas_free(ee);
+ return NULL;
+ }
+ if ((id = getenv("DESKTOP_STARTUP_ID")))
+ {
+ ecore_x_netwm_startup_id_set(ee->prop.window, id);
+ /* NB: on linux this may simply empty the env as opposed to completely
+ * unset it to being empty - unsure as solartis libc crashes looking
+ * for the '=' char */
+// putenv((char*)"DESKTOP_STARTUP_ID=");
+ }
+
+ _ecore_evas_x_hints_update(ee);
+ _ecore_evas_x_group_leader_set(ee);
+ ecore_x_window_defaults_set(ee->prop.window);
+ _ecore_evas_x_protocols_set(ee);
+ _ecore_evas_x_sync_set(ee);
+
+ ee->engine.func->fn_render = _ecore_evas_x_render;
+ _ecore_evas_register(ee);
+ ecore_x_input_multi_select(ee->prop.window);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ return ee;
+}
+#else
+EAPI Ecore_Evas *
+ecore_evas_gl_x11_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED,
+ int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+EAPI Ecore_Evas *
+ecore_evas_gl_x11_options_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED,
+ int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, const int *opt EINA_UNUSED)
+{
+ return NULL;
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+/**
+ * @brief Get the window from Ecore_Evas using opengl x11.
+ * @note If ecore is not compiled with support for x11 or if @p ee was not
+ * created with ecore_evas_gl_x11_new() then nothing is done and
+ * 0 is returned.
+ * @param ee The Ecore_Evas from which to get the window.
+ * @return The window of type Ecore_X_Window of Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI Ecore_X_Window
+ecore_evas_gl_x11_window_get(const Ecore_Evas *ee)
+{
+ if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
+ return (Ecore_X_Window) ecore_evas_window_get(ee);
+}
+#else
+EAPI Ecore_X_Window
+ecore_evas_gl_x11_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+/**
+ * @brief Set direct_resize for Ecore_Evas using opengl x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done.
+ * @param ee The Ecore_Evas in which to set direct resize.
+ * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI void
+ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on)
+{
+ ee->engine.x.direct_resize = on;
+}
+#else
+EAPI void
+ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee EINA_UNUSED, Eina_Bool on EINA_UNUSED)
+{
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+/**
+ * @brief Gets if the Ecore_Evas is being directly resized using opengl x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done and EINA_FALSE is returned.
+ * @param ee The Ecore_Evas from which to get direct resize.
+ * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI Eina_Bool
+ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee)
+{
+ return ee->engine.x.direct_resize;
+}
+#else
+EAPI Eina_Bool
+ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+/**
+ * @brief Add extra window on Ecore_Evas using opengl x11.
+ * @note If ecore is not compiled with support to x11 then nothing is done.
+ * @param ee The Ecore_Evas for which to add the window.
+ * @param win The window to be added at the Ecore_Evas.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI void
+ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win)
+{
+ ecore_evas_software_x11_extra_event_window_add(ee, win);
+}
+#else
+EAPI void
+ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee EINA_UNUSED, Ecore_X_Window win EINA_UNUSED)
+{
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+/**
+ * @brief Set the functions to be used before and after the swap callback.
+ * @note If ecore is not compiled with support to x11 then nothing is done and the function is returned.
+ * @param ee The Ecore_Evas for which to set the swap callback.
+ * @param data The data for which to set the swap callback.
+ * @param pre_cb The function to be called before the callback.
+ * @param post_cb The function to be called after the callback.
+ */
+#ifdef BUILD_ECORE_EVAS_OPENGL_X11
+EAPI void
+ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee, void *data, void (*pre_cb) (void *data, Evas *e), void (*post_cb) (void *data, Evas *e))
+{
+ Evas_Engine_Info_GL_X11 *einfo;
+
+ if (!(!strcmp(ee->driver, "opengl_x11"))) return;
+
+ einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ einfo->callback.pre_swap = pre_cb;
+ einfo->callback.post_swap = post_cb;
+ einfo->callback.data = data;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ }
+ }
+}
+#else
+EAPI void
+ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee EINA_UNUSED, void *data EINA_UNUSED, void (*pre_cb) (void *data, Evas *e) EINA_UNUSED, void (*post_cb) (void *data, Evas *e) EINA_UNUSED)
+{
+ return;
+}
+#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
+
+EAPI Ecore_Evas *
+ecore_evas_xrender_x11_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED,
+ int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_X_Window
+ecore_evas_xrender_x11_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_xrender_x11_direct_resize_set(Ecore_Evas *ee EINA_UNUSED, Eina_Bool on EINA_UNUSED)
+{
+}
+
+EAPI Eina_Bool
+ecore_evas_xrender_x11_direct_resize_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_xrender_x11_extra_event_window_add(Ecore_Evas *ee EINA_UNUSED, Ecore_X_Window win EINA_UNUSED)
+{
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_x11_16_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED,
+ int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_X_Window
+ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee EINA_UNUSED, Eina_Bool on EINA_UNUSED)
+{
+}
+
+EAPI Eina_Bool
+ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee EINA_UNUSED, Ecore_X_Window win EINA_UNUSED)
+{
+}
+
+EAPI Ecore_Evas *
+ecore_evas_software_x11_8_new(const char *disp_name EINA_UNUSED, Ecore_X_Window parent EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ return NULL;
+}
+
+EAPI Ecore_X_Window
+ecore_evas_software_x11_8_window_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI Ecore_X_Window
+ecore_evas_software_x11_8_subwindow_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_software_x11_8_direct_resize_set(Ecore_Evas *ee EINA_UNUSED, Eina_Bool on EINA_UNUSED)
+{
+}
+
+EAPI Eina_Bool
+ecore_evas_software_x11_8_direct_resize_get(const Ecore_Evas *ee EINA_UNUSED)
+{
+ return 0;
+}
+
+EAPI void
+ecore_evas_software_x11_8_extra_event_window_add(Ecore_Evas *ee EINA_UNUSED, Ecore_X_Window win EINA_UNUSED)
+{
+ return;
+}
+
+EAPI void
+ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ _ecore_evas_x_group_leader_unset(ee);
+ ee->engine.x.leader = win;
+ _ecore_evas_x_group_leader_update(ee);
+#else
+ return;
+ ee = NULL;
+ win = 0;
+#endif
+}
+
+EAPI Ecore_X_Window
+ecore_evas_x11_leader_get(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ return ee->engine.x.leader;
+#else
+ return 0;
+ ee = NULL;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_leader_default_set(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ _ecore_evas_x_group_leader_unset(ee);
+ _ecore_evas_x_group_leader_set(ee);
+#else
+ return;
+ ee = NULL;
+#endif
+}
+
+#ifdef BUILD_ECORE_EVAS_X11
+static Eina_Bool
+_ecore_evas_x11_convert_rectangle_with_angle(Ecore_Evas *ee, Ecore_X_Rectangle *dst_rect, Ecore_X_Rectangle *src_rect)
+{
+ if ((!src_rect) || (!dst_rect)) return 0;
+
+ if (ee->rotation == 0)
+ {
+ dst_rect->x = src_rect->x;
+ dst_rect->y = src_rect->y;
+ dst_rect->width = src_rect->width;
+ dst_rect->height = src_rect->height;
+ }
+ else if (ee->rotation == 90)
+ {
+ dst_rect->x = src_rect->y;
+ dst_rect->y = ee->req.h - src_rect->x - src_rect->width;
+ dst_rect->width = src_rect->height;
+ dst_rect->height = src_rect->width;
+ }
+ else if (ee->rotation == 180)
+ {
+ dst_rect->x = ee->req.w - src_rect->x - src_rect->width;
+ dst_rect->y = ee->req.h - src_rect->y - src_rect->height;
+ dst_rect->width = src_rect->width;
+ dst_rect->height = src_rect->height;
+ }
+ else if (ee->rotation == 270)
+ {
+ dst_rect->x = ee->req.w - src_rect->y - src_rect->height;
+ dst_rect->y = src_rect->x;
+ dst_rect->width = src_rect->height;
+ dst_rect->height = src_rect->width;
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+EAPI void
+ecore_evas_x11_shape_input_rectangle_set(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ Eina_Bool ret;
+ Ecore_X_Rectangle src_rect;
+ Ecore_X_Rectangle dst_rect;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_rectangle_set");
+ return;
+ }
+
+ src_rect.x = x;
+ src_rect.y = y;
+ src_rect.width = w;
+ src_rect.height = h;
+
+ dst_rect.x = 0;
+ dst_rect.y = 0;
+ dst_rect.width = 0;
+ dst_rect.height = 0;
+
+ ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
+
+ if (!ee->engine.x.win_shaped_input)
+ ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root,
+ 0, 0, 1, 1);
+
+ if (ret)
+ ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input,
+ dst_rect.x, dst_rect.y,
+ dst_rect.width, dst_rect.height);
+#else
+ return;
+ ee = NULL;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ Eina_Bool ret;
+ Ecore_X_Rectangle src_rect;
+ Ecore_X_Rectangle dst_rect;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_rectangle_add");
+ return;
+ }
+
+ src_rect.x = x;
+ src_rect.y = y;
+ src_rect.width = w;
+ src_rect.height = h;
+
+ dst_rect.x = 0;
+ dst_rect.y = 0;
+ dst_rect.width = 0;
+ dst_rect.height = 0;
+
+ ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
+
+ if (!ee->engine.x.win_shaped_input)
+ ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root,
+ 0, 0, 1, 1);
+
+ if (ret)
+ ecore_x_window_shape_input_rectangle_add(ee->engine.x.win_shaped_input,
+ dst_rect.x, dst_rect.y,
+ dst_rect.width, dst_rect.height);
+#else
+ return;
+ ee = NULL;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ Eina_Bool ret;
+ Ecore_X_Rectangle src_rect;
+ Ecore_X_Rectangle dst_rect;
+
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_rectangle_subtract");
+ return;
+ }
+
+ src_rect.x = x;
+ src_rect.y = y;
+ src_rect.width = w;
+ src_rect.height = h;
+
+ dst_rect.x = 0;
+ dst_rect.y = 0;
+ dst_rect.width = 0;
+ dst_rect.height = 0;
+
+ ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
+
+ if (!ee->engine.x.win_shaped_input)
+ ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root,
+ 0, 0, 1, 1);
+
+ if (ret)
+ ecore_x_window_shape_input_rectangle_subtract(ee->engine.x.win_shaped_input,
+ dst_rect.x, dst_rect.y,
+ dst_rect.width, dst_rect.height);
+#else
+ return;
+ ee = NULL;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_shape_input_empty(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_empty");
+ return;
+ }
+
+ if (!ee->engine.x.win_shaped_input)
+ ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, 0, 0, 1, 1);
+
+ ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input, 0, 0, 0, 0);
+#else
+ return;
+ ee = NULL;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_shape_input_reset(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_reset");
+ return;
+ }
+
+ if (!ee->engine.x.win_shaped_input)
+ ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, 0, 0, 1, 1);
+
+ ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input, 0, 0, 65535, 65535);
+#else
+ return;
+ ee = NULL;
+#endif
+}
+
+EAPI void
+ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
+{
+#ifdef BUILD_ECORE_EVAS_X11
+ if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
+ {
+ ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
+ "ecore_evas_x11_shape_input_apply");
+ return;
+ }
+
+ if (!ee->engine.x.win_shaped_input) return;
+
+ ecore_x_window_shape_input_window_set(ee->prop.window, ee->engine.x.win_shaped_input);
+#else
+ return;
+ ee = NULL;
+#endif
+}
diff --git a/src/lib/ecore_fb/Ecore_Fb.h b/src/lib/ecore_fb/Ecore_Fb.h
new file mode 100644
index 0000000000..069cccdff9
--- /dev/null
+++ b/src/lib/ecore_fb/Ecore_Fb.h
@@ -0,0 +1,100 @@
+#ifndef _ECORE_FB_H
+#define _ECORE_FB_H
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+#else
+# define EAPI
+#endif
+
+/* FIXME:
+ * maybe a new module?
+ * - code to get battery info
+ * - code to get thermal info
+ * ecore evas fb isn't good enough for weird things, like multiple fb's, same happens here.
+ * backlight support using new kernel interface
+ * absolute axis
+ * joystick
+ * ecore_fb_li_device_close_all ? or a shutdown of the subsystem?
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
+ *
+ * Functions used to set up and shut down the Ecore_Framebuffer functions.
+ *
+ * @{
+ */
+
+/**
+ * @typedef Ecore_Fb_Input_Device
+ * Input device handler.
+ */
+typedef struct _Ecore_Fb_Input_Device Ecore_Fb_Input_Device;
+
+/**
+ * @enum _Ecore_Fb_Input_Device_Cap
+ * Device capabilities.
+ */
+enum _Ecore_Fb_Input_Device_Cap
+{
+ ECORE_FB_INPUT_DEVICE_CAP_NONE = 0x00000000,
+ ECORE_FB_INPUT_DEVICE_CAP_RELATIVE = 0x00000001,
+ ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE = 0x00000002,
+ ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS = 0x00000004
+};
+
+/**
+ * @typedef Ecore_Fb_Input_Device_Cap
+ * Device capabilities.
+ */
+typedef enum _Ecore_Fb_Input_Device_Cap Ecore_Fb_Input_Device_Cap;
+
+/* ecore_fb_vt.c */
+EAPI void ecore_fb_callback_gain_set(void (*func) (void *data), void *data);
+EAPI void ecore_fb_callback_lose_set(void (*func) (void *data), void *data);
+
+/* ecore_fb_li.c */
+EAPI Ecore_Fb_Input_Device *ecore_fb_input_device_open(const char *dev);
+EAPI void ecore_fb_input_device_close(Ecore_Fb_Input_Device *dev);
+EAPI void ecore_fb_input_device_listen(Ecore_Fb_Input_Device *dev, Eina_Bool listen);
+EAPI const char *ecore_fb_input_device_name_get(Ecore_Fb_Input_Device *dev);
+EAPI Ecore_Fb_Input_Device_Cap ecore_fb_input_device_cap_get(Ecore_Fb_Input_Device *dev);
+EAPI void ecore_fb_input_device_axis_size_set(Ecore_Fb_Input_Device *dev, int w, int h);
+EAPI void ecore_fb_input_threshold_click_set(Ecore_Fb_Input_Device *dev, double threshold);
+EAPI double ecore_fb_input_threshold_click_get(Ecore_Fb_Input_Device *dev);
+EAPI void ecore_fb_input_device_window_set(Ecore_Fb_Input_Device *dev, void *window);
+
+/* ecore_fb.c */
+
+EAPI int ecore_fb_init(const char *name);
+EAPI int ecore_fb_shutdown(void);
+EAPI void ecore_fb_size_get(int *w, int *h);
+
+EAPI void ecore_fb_touch_screen_calibrate_set(int xscale, int xtrans, int yscale, int ytrans, int xyswap);
+EAPI void ecore_fb_touch_screen_calibrate_get(int *xscale, int *xtrans, int *yscale, int *ytrans, int *xyswap);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_fb/ecore_fb.c b/src/lib/ecore_fb/ecore_fb.c
new file mode 100644
index 0000000000..ff96ac8a77
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb.c
@@ -0,0 +1,129 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Ecore_Fb.h"
+#include "ecore_fb_private.h"
+
+static void _ecore_fb_size_get(int *w, int *h);
+
+static int _ecore_fb_init_count = 0;
+static int _ecore_fb_console_w = 0;
+static int _ecore_fb_console_h = 0;
+
+/**
+ * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
+ *
+ * @{
+ */
+
+static sighandler_t oldhand = NULL;
+
+static void
+nosigint(int val EINA_UNUSED)
+{
+}
+
+/**
+ * @brief Initialize the Ecore_Fb library.
+ *
+ * @param name Device target name.
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up all the Ecore_Fb library. It returns 0 on
+ * failure, otherwise it returns the number of times it has already
+ * been called.
+ *
+ * When Ecore_Fb is not used anymore, call ecore_fb_shutdown() to shut down
+ * the Ecore_Fb library.
+ */
+EAPI int
+ecore_fb_init(const char *name EINA_UNUSED)
+{
+ if (++_ecore_fb_init_count != 1)
+ return _ecore_fb_init_count;
+
+ if (!ecore_fb_vt_init())
+ return --_ecore_fb_init_count;
+
+ if (!oldhand)
+ {
+ oldhand = signal(SIGINT, nosigint);
+ }
+
+ _ecore_fb_size_get(&_ecore_fb_console_w, &_ecore_fb_console_h);
+
+ return _ecore_fb_init_count;
+}
+
+/**
+ * @brief Shut down the Ecore_Fb library.
+ *
+ * @return 0 when the library is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Ecore_Fb library. It returns 0 when it has
+ * been called the same number of times than ecore_fb_init().
+ */
+EAPI int
+ecore_fb_shutdown(void)
+{
+ if (--_ecore_fb_init_count != 0)
+ return _ecore_fb_init_count;
+
+ if (oldhand)
+ {
+ signal(SIGINT, oldhand);
+ oldhand = NULL;
+ }
+
+ ecore_fb_vt_shutdown();
+
+ return _ecore_fb_init_count;
+}
+
+
+/**
+ * @brief Retrieve the width and height of the current frame buffer in
+ * pixels.
+ *
+ * @param w Pointer to an integer in which to store the width.
+ * @param h Pointer to an interge in which to store the height.
+ *
+ * This function retrieves the size of the current frame buffer in
+ * pixels. @p w and @p h can be buffers that will be filled with the
+ * corresponding values. If one of them is @c NULL, nothing will be
+ * done for that parameter.
+ */
+EAPI void
+ecore_fb_size_get(int *w, int *h)
+{
+ if (w) *w = _ecore_fb_console_w;
+ if (h) *h = _ecore_fb_console_h;
+}
+
+static void
+_ecore_fb_size_get(int *w, int *h)
+{
+ struct fb_var_screeninfo fb_var;
+ int fb;
+
+ fb = open("/dev/fb0", O_RDWR);
+ if (fb < 0)
+ goto exit;
+
+ if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) == -1)
+ goto err_ioctl;
+
+ *w = fb_var.xres;
+ *h = fb_var.yres;
+
+err_ioctl:
+ close(fb);
+exit:
+ return;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_fb/ecore_fb_kbd.c b/src/lib/ecore_fb/ecore_fb_kbd.c
new file mode 100644
index 0000000000..fd111db04d
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_kbd.c
@@ -0,0 +1,326 @@
+static void _ecore_fb_event_free_key_down(void *data, void *ev);
+static void _ecore_fb_event_free_key_up(void *data, void *ev);
+
+static const char *_ecore_fb_kbd_syms[128 * 7] =
+{
+#include "ecore_fb_keytable.h"
+};
+
+static const char *_ecore_fb_btn_syms[128] =
+{
+ "0x00",
+ "Escape",
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "Up",
+ "Right",
+ "Left",
+ "Down",
+ "Return",
+ "0x1b",
+ "0x1c",
+ "0x1d",
+ "0x1e",
+ "0x1f",
+ "0x20",
+ "0x21",
+ "0x22",
+ "0x23",
+ "0x24",
+ "0x25",
+ "0x26",
+ "0x27",
+ "0x28",
+ "0x29",
+ "0x2a",
+ "0x2b",
+ "0x2c",
+ "0x2d",
+ "0x2e",
+ "0x2f",
+ "0x30",
+ "0x31",
+ "0x32",
+ "0x33",
+ "0x34",
+ "0x35",
+ "0x36",
+ "0x37",
+ "0x38",
+ "0x39",
+ "0x3a",
+ "0x3b",
+ "0x3c",
+ "0x3d",
+ "0x3e",
+ "0x3f",
+ "0x40",
+ "0x41",
+ "0x42",
+ "0x43",
+ "0x44",
+ "0x45",
+ "0x46",
+ "0x47",
+ "0x48",
+ "0x49",
+ "0x4a",
+ "0x4b",
+ "0x4c",
+ "0x4d",
+ "0x4e",
+ "0x4f",
+ "0x50",
+ "0x51",
+ "0x52",
+ "0x53",
+ "0x54",
+ "0x55",
+ "0x56",
+ "0x57",
+ "0x58",
+ "0x59",
+ "0x5a",
+ "0x5b",
+ "0x5c",
+ "0x5d",
+ "0x5e",
+ "0x5f",
+ "0x60",
+ "0x61",
+ "0x62",
+ "0x63",
+ "0x64",
+ "0x65",
+ "0x66",
+ "0x67",
+ "0x68",
+ "0x69",
+ "0x6a",
+ "0x6b",
+ "0x6c",
+ "0x6d",
+ "0x6e",
+ "0x6f",
+ "0x70",
+ "0x71",
+ "0x72",
+ "0x73",
+ "0x74",
+ "0x75",
+ "0x76",
+ "0x77",
+ "0x78",
+ "0x79",
+ "0x7a",
+ "0x7b",
+ "0x7c",
+ "0x7d",
+ "0x7e",
+ "0x7f"
+};
+static int _ecore_fb_kbd_fd = -1;
+static int _ecore_fb_ctrl = 0;
+static int _ecore_fb_alt = 0;
+static int _ecore_fb_shift = 0;
+static int _ecore_fb_lock = 0;
+
+static Ecore_Fd_Handler *_ecore_fb_kbd_fd_handler_handle = NULL;
+static Eina_Bool _ecore_fb_kbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
+
+static void
+_ecore_fb_event_free_key_down(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Fb_Event_Key_Down *e;
+ e = ev;
+ free(e->keyname);
+ if (e->keysymbol) free(e->keysymbol);
+ if (e->key_compose) free(e->key_compose);
+ free(e);
+}
+
+static void
+_ecore_fb_event_free_key_up(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Fb_Event_Key_Up *e;
+
+ e = ev;
+ free(e->keyname);
+ if (e->keysymbol) free(e->keysymbol);
+ if (e->key_compose) free(e->key_compose);
+ free(e);
+}
+
+static Eina_Bool
+_ecore_fb_kbd_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ int v = 0;
+
+ do
+ {
+ unsigned char buf;
+
+ v = read(_ecore_fb_kbd_fd, &buf, 1);
+ if (v < 0) return EINA_TRUE;
+ if (v < 1) return EINA_TRUE;
+ if (!(buf & 0x80))
+ {
+ /* DOWN */
+ int vt_switch = -1;
+ Ecore_Fb_Event_Key_Down *e;
+
+ e = calloc(1, sizeof(Ecore_Fb_Event_Key_Down));
+ if (!e) goto retry;
+ if (_ecore_fb_kbd_fd == _ecore_fb_tty_fd)
+ {
+ int add = 0;
+
+ if (_ecore_fb_shift) add = 1;
+ else if (_ecore_fb_lock) add = 2;
+ e->keyname = strdup(_ecore_fb_kbd_syms[(buf & 0x7f) * 7]);
+ e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + add]);
+ e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + 3 + add]);
+ }
+ else
+ e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]);
+ if (!e->keyname)
+ {
+ free(e);
+ goto retry;
+ }
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ if (!strcmp(e->keyname, "Control_L"))
+ _ecore_fb_ctrl++;
+ else if (!strcmp(e->keyname, "Control_R"))
+ _ecore_fb_ctrl++;
+ else if (!strcmp(e->keyname, "Alt_L"))
+ _ecore_fb_alt++;
+ else if (!strcmp(e->keyname, "Alt_R"))
+ _ecore_fb_alt++;
+ else if (!strcmp(e->keyname, "Shift_L"))
+ _ecore_fb_shift++;
+ else if (!strcmp(e->keyname, "Shift_R"))
+ _ecore_fb_shift++;
+ else if (!strcmp(e->keyname, "Caps_Lock"))
+ _ecore_fb_lock++;
+ else if (!strcmp(e->keyname, "F1")) vt_switch = 0;
+ else if (!strcmp(e->keyname, "F2")) vt_switch = 1;
+ else if (!strcmp(e->keyname, "F3")) vt_switch = 2;
+ else if (!strcmp(e->keyname, "F4")) vt_switch = 3;
+ else if (!strcmp(e->keyname, "F5")) vt_switch = 4;
+ else if (!strcmp(e->keyname, "F6")) vt_switch = 5;
+ else if (!strcmp(e->keyname, "F7")) vt_switch = 6;
+ else if (!strcmp(e->keyname, "F8")) vt_switch = 7;
+ else if (!strcmp(e->keyname, "F9")) vt_switch = 8;
+ else if (!strcmp(e->keyname, "F10")) vt_switch = 9;
+ else if (!strcmp(e->keyname, "F11")) vt_switch = 10;
+ else if (!strcmp(e->keyname, "F12")) vt_switch = 11;
+ if (_ecore_fb_ctrl > 2) _ecore_fb_ctrl = 2;
+ if (_ecore_fb_alt > 2) _ecore_fb_alt = 2;
+ if ((_ecore_fb_kbd_fd == _ecore_fb_tty_fd) &&
+ (_ecore_fb_ctrl))
+ {
+ const char *ts = _ecore_fb_kbd_syms[(buf & 0x7f) + 3 + 3];
+
+ if (ts)
+ {
+ if (e->key_compose) free(e->key_compose);
+ e->key_compose = strdup(ts);
+ }
+ }
+ if ((vt_switch >= 0) &&
+ (_ecore_fb_ctrl) &&
+ (_ecore_fb_alt))
+ _ecore_fb_vt_switch(vt_switch);
+ ecore_event_add(ECORE_FB_EVENT_KEY_DOWN, e, _ecore_fb_event_free_key_down, NULL);
+ }
+ else
+ {
+ /* UP */
+ Ecore_Fb_Event_Key_Up *e;
+
+ e = calloc(1, sizeof(Ecore_Fb_Event_Key_Up));
+ if (!e) goto retry;
+ if (_ecore_fb_kbd_fd == _ecore_fb_tty_fd)
+ {
+ int add = 0;
+
+ if (_ecore_fb_shift) add = 1;
+ else if (_ecore_fb_lock) add = 2;
+ e->keyname = strdup(_ecore_fb_kbd_syms[(buf & 0x7f) * 7]);
+ e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + add]);
+ e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + 3 + add]);
+ }
+ else
+ e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]);
+ if (!e->keyname)
+ {
+ free(e);
+ goto retry;
+ }
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_FB_EVENT_KEY_UP, e, _ecore_fb_event_free_key_up, NULL);
+ if (!strcmp(e->keyname, "Control_L"))
+ _ecore_fb_ctrl--;
+ else if (!strcmp(e->keyname, "Control_R"))
+ _ecore_fb_ctrl--;
+ else if (!strcmp(e->keyname, "Alt_L"))
+ _ecore_fb_alt--;
+ else if (!strcmp(e->keyname, "Alt_R"))
+ _ecore_fb_alt--;
+ else if (!strcmp(e->keyname, "Shift_L"))
+ _ecore_fb_shift--;
+ else if (!strcmp(e->keyname, "Shift_R"))
+ _ecore_fb_shift--;
+ else if (!strcmp(e->keyname, "Caps_Lock"))
+ _ecore_fb_lock--;
+ if (_ecore_fb_ctrl < 0) _ecore_fb_ctrl = 0;
+ if (_ecore_fb_alt < 0) _ecore_fb_alt = 0;
+ if (_ecore_fb_shift < 0) _ecore_fb_shift = 0;
+ if (_ecore_fb_lock < 0) _ecore_fb_lock = 0;
+ }
+retry:
+ ;
+ }
+ while (v > 0);
+ return EINA_TRUE;
+}
+
+int
+ecore_fb_kbd_init(void)
+{
+ int prev_flags;
+
+ prev_flags = fcntl(_ecore_fb_kbd_fd, F_GETFL);
+ fcntl(_ecore_fb_kbd_fd, F_SETFL, prev_flags | O_NONBLOCK);
+ _ecore_fb_kbd_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_kbd_fd,
+ ECORE_FD_READ,
+ _ecore_fb_kbd_fd_handler, NULL,
+ NULL, NULL);
+ if(!_ecore_fb_kbd_fd_handler_handle) return 0;
+ return 1;
+}
+
+void
+ecore_fb_kbd_shutdown(void)
+{
+ if (_ecore_fb_kbd_fd_handler_handle)
+ ecore_main_fd_handler_del(_ecore_fb_kbd_fd_handler_handle);
+ if (_ecore_fb_kbd_fd >= 0) close(_ecore_fb_kbd_fd);
+ _ecore_fb_kbd_fd = -1;
+ _ecore_fb_kbd_fd_handler_handle = NULL;
+ _ecore_fb_ctrl = 0;
+ _ecore_fb_lock = 0;
+ _ecore_fb_shift = 0;
+ _ecore_fb_alt = 0;
+}
diff --git a/src/lib/ecore_fb/ecore_fb_keytable.h b/src/lib/ecore_fb/ecore_fb_keytable.h
new file mode 100644
index 0000000000..70bf6b9689
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_keytable.h
@@ -0,0 +1,129 @@
+/* this table was taken from ecore_fb, is the default en layout */
+ "0x00", "0x00", "0x00", /**/"", "", "", NULL,/***/
+ "Escape", "Escape", "Escape", /**/"", "", "", "\x1b",/***/
+ "1", "exclam", "1", /**/"1", "!", "1", NULL,/***/
+ "2", "at", "2", /**/"2", "@", "2", "",/***/
+ "3", "numbersign", "3", /**/"3", "#", "3", "\x1b",/***/
+ "4", "dollar", "4", /**/"4", "$", "4", "\x1c",/***/
+ "5", "percent", "5", /**/"5", "%", "5", "\x1d",/***/
+ "6", "asciicircumm", "6", /**/"6", "^", "6", "\x1e",/***/
+ "7", "ampersand", "7", /**/"7", "&", "7", "\x1f",/***/
+ "8", "asterisk", "8", /**/"8", "*", "8", "\x7f",/***/
+ "9", "parenleft", "9", /**/"9", "(", "9", NULL,/***/
+ "0", "parenright", "0", /**/"0", ")", "0", NULL,/***/
+ "minus", "underscore", "minus", /**/"-", "_", "-", NULL,/***/
+ "equal", "plus", "equal", /**/"=", "+", "=", NULL,/***/
+ "BackSpace", "BackSpace", "BackSpace", /**/"\010","\010","\010", NULL,/***/
+ "Tab", "ISO_Left_Tab", "Tab", /**/"\011","", "\011", NULL,/***/
+ "q", "Q", "Q", /**/"q", "Q", "Q", "\x11",/***/
+ "w", "W", "W", /**/"w", "W", "W", "\x17",/***/
+ "e", "E", "E", /**/"e", "E", "E", "\x05",/***/
+ "r", "R", "R", /**/"r", "R", "R", "\x12",/***/
+ "t", "T", "T", /**/"t", "T", "T", "\x14",/***/
+ "y", "Y", "Y", /**/"y", "Y", "Y", "\x19",/***/
+ "u", "U", "U", /**/"u", "U", "U", "\x15",/***/
+ "i", "I", "I", /**/"i", "I", "I", "\x09",/***/
+ "o", "O", "O", /**/"o", "O", "O", "\x0f",/***/
+ "p", "P", "P", /**/"p", "P", "P", "\x10",/***/
+ "bracketleft", "braceleft", "bracketleft", /**/"[", "{", "[", "\x1b",/***/
+ "bracketright", "braceright", "bracketright", /**/"]", "}", "]", "\x1d",/***/
+ "Return", "Return", "Return", /**/"\015","\015","\015", NULL,/***/
+ "Control_L", "Control_L", "Control_L", /**/"", "", "", NULL,/***/
+ "a", "A", "A", /**/"a", "A", "A", "\x01",/***/
+ "s", "S", "S", /**/"s", "S", "S", "\x13",/***/
+ "d", "D", "D", /**/"d", "D", "D", "\x04",/***/
+ "f", "F", "F", /**/"f", "F", "F", "\x06",/***/
+ "g", "G", "G", /**/"g", "G", "G", "\x07",/***/
+ "h", "h", "H", /**/"h", "H", "H", "\x08",/***/
+ "j", "J", "J", /**/"j", "J", "J", "\x0a",/***/
+ "k", "K", "K", /**/"k", "K", "K", "\x0b",/***/
+ "l", "L", "L", /**/"l", "L", "L", "\x0c",/***/
+ "semicolon", "colon", "semicolon", /**/";", ":", ";", NULL,/***/
+ "apostrophe", "quotedbl", "apostrophe", /**/"'", "\"", "'", NULL,/***/
+ "grave", "asciitilde", "grave", /**/"`", "~", "`", "",/***/
+ "Shift_L", "Shift_L", "Shift_L", /**/"", "", "", NULL,/***/
+ "backslash", "bar", "backslash", /**/"\\", "|", "\\", "\x1c",/***/
+ "z", "Z", "Z", /**/"z", "Z", "Z", "\x1a",/***/
+ "x", "X", "X", /**/"x", "X", "X", "\x18",/***/
+ "c", "C", "C", /**/"c", "C", "C", "\x03",/***/
+ "v", "V", "V", /**/"v", "V", "V", "\x16",/***/
+ "b", "B", "B", /**/"b", "B", "B", "\x02",/***/
+ "n", "N", "N", /**/"n", "N", "N", "\x0e",/***/
+ "m", "M", "M", /**/"m", "M", "M", "\x0d",/***/
+ "comma", "less", "comma", /**/",", "<", ",", NULL,/***/
+ "period", "greater", "period", /**/".", ">", ".", NULL,/***/
+ "slash", "question", "slash", /**/"/", "?", "/", "",/***/
+ "Shift_R", "Shift_R", "Shift_R", /**/"", "", "", NULL,/***/
+ "KP_Multiply", "KP_Multiply", "KP_Multiply", /**/"", "*", "", NULL,/***/
+ "Alt_L", "Alt_L", "Alt_L", /**/"", "", "", NULL,/***/
+ "space", "space", "space", /**/" ", " ", " ", "",/***/
+ "Caps_Lock", "Caps_Lock", "Caps_Lock", /**/"", "", "", NULL,/***/
+ "F1", "F1", "F1", /**/"", "", "", NULL,/***/
+ "F2", "F2", "F2", /**/"", "", "", NULL,/***/
+ "F3", "F3", "F3", /**/"", "", "", NULL,/***/
+ "F4", "F4", "F4", /**/"", "", "", NULL,/***/
+ "F5", "F5", "F5", /**/"", "", "", NULL,/***/
+ "F6", "F6", "F6", /**/"", "", "", NULL,/***/
+ "F7", "F7", "F7", /**/"", "", "", NULL,/***/
+ "F8", "F8", "F8", /**/"", "", "", NULL,/***/
+ "F9", "F9", "F9", /**/"", "", "", NULL,/***/
+ "F10", "F10", "F10", /**/"", "", "", NULL,/***/
+ "Num_Lock", "Num_Lock", "Num_Lock", /**/"", "", "", NULL,/***/
+ "Scroll_Lock", "Scroll_Lock", "Scroll_Lock", /**/"", "", "", NULL,/***/
+ "KP_Home", "KP_7", "KP_Home", /**/"", "7", "", NULL,/***/
+ "KP_Up", "KP_8", "KP_Up", /**/"", "8", "", NULL,/***/
+ "KP_Prior", "KP_9", "KP_Prior", /**/"", "9", "", NULL,/***/
+ "KP_Subtract", "KP_Subtract", "KP_Subtract", /**/"", "", "", NULL,/***/
+ "KP_Left", "KP_4", "KP_Left", /**/"", "4", "", NULL,/***/
+ "KP_Begin", "KP_5", "KP_Begin", /**/"", "5", "", NULL,/***/
+ "KP_Right", "KP_6", "KP_Right", /**/"", "6", "", NULL,/***/
+ "KP_Add", "KP_Add", "KP_Add", /**/"", "", "", NULL,/***/
+ "KP_End", "KP_1", "KP_End", /**/"", "1", "", NULL,/***/
+ "KP_Down", "KP_2", "KP_Down", /**/"", "2", "", NULL,/***/
+ "KP_Next", "KP_3", "KP_Next", /**/"", "3", "", NULL,/***/
+ "KP_Insert", "KP_0", "KP_Insert", /**/"", "0", "", NULL,/***/
+ "KP_Delete", "KP_Decimal", "KP_Delete", /**/"", ".", "", NULL,/***/
+ "0x54", "0x54", "0x54", /**/"", "", "", NULL,/***/
+ "0x55", "0x55", "0x55", /**/"", "", "", NULL,/***/
+ "0x56", "0x56", "0x56", /**/"", "", "", NULL,/***/
+ "F11", "F11", "F11", /**/"", "", "", NULL,/***/
+ "F12", "F12", "F12", /**/"", "", "", NULL,/***/
+ "0x59", "0x59", "0x59", /**/"", "", "", NULL,/***/
+ "0x5a", "0x5a", "0x5a", /**/"", "", "", NULL,/***/
+ "0x5b", "0x5b", "0x5b", /**/"", "", "", NULL,/***/
+ "0x5c", "0x5c", "0x5c", /**/"", "", "", NULL,/***/
+ "0x5d", "0x5d", "0x5d", /**/"", "", "", NULL,/***/
+ "0x5e", "0x5e", "0x5e", /**/"", "", "", NULL,/***/
+ "0x5f", "0x5f", "0x5f", /**/"", "", "", NULL,/***/
+ "KP_Enter", "KP_Enter", "KP_Enter", /**/"\015", "\015", "\015", NULL,/***/
+ "Control_R", "Control_R", "Control_R", /**/"", "", "", NULL,/***/
+ "KP_Divide", "KP_Divide", "KP_Divide", /**/"", "", "", NULL,/***/
+ "Print", "Print", "Print", /**/"", "", "", NULL,/***/
+ "Alt_R", "Alt_R", "Alt_R", /**/"", "", "", NULL,/***/
+ "0x65", "0x65", "0x65", /**/"", "", "", NULL,/***/
+ "Home", "Home", "Home", /**/"", "", "", NULL,/***/
+ "Up", "Up", "Up", /**/"", "", "", NULL,/***/
+ "Prior", "Prior", "Prior", /**/"", "", "", NULL,/***/
+ "Left", "Left", "Left", /**/"", "", "", NULL,/***/
+ "Right", "Right", "Right", /**/"", "", "", NULL,/***/
+ "End", "End", "End", /**/"", "", "", NULL,/***/
+ "Down", "Down", "Down", /**/"", "", "", NULL,/***/
+ "Next", "Next", "Next", /**/"", "", "", NULL,/***/
+ "Insert", "Insert", "Insert", /**/"", "", "", NULL,/***/
+ "Delete", "Delete", "Delete", /**/"\177","\177","\177", NULL,/***/
+ "0x70", "0x70", "0x70", /**/"", "", "", NULL,/***/
+ "0x71", "0x71", "0x71", /**/"", "", "", NULL,/***/
+ "0x72", "0x72", "0x72", /**/"", "", "", NULL,/***/
+ "0x73", "0x73", "0x73", /**/"", "", "", NULL,/***/
+ "0x74", "0x74", "0x74", /**/"", "", "", NULL,/***/
+ "0x75", "0x75", "0x75", /**/"", "", "", NULL,/***/
+ "0x76", "0x76", "0x76", /**/"", "", "", NULL,/***/
+ "Pause", "Pause", "Pause", /**/"", "", "", NULL,/***/
+ "0x78", "0x78", "0x78", /**/"", "", "", NULL,/***/
+ "0x79", "0x79", "0x79", /**/"", "", "", NULL,/***/
+ "0x7a", "0x7a", "0x7a", /**/"", "", "", NULL,/***/
+ "0x7b", "0x7b", "0x7b", /**/"", "", "", NULL,/***/
+ "0x7c", "0x7c", "0x7c", /**/"", "", "", NULL,/***/
+ "Super_L", "Super_L", "Super_L", /**/"", "", "", NULL,/***/
+ "Super_R", "Super_R", "Super_R", /**/"", "", "", NULL,/***/
+ "0x7f", "0x7f", "0x7f", /**/"", "", "", NULL, /***/
diff --git a/src/lib/ecore_fb/ecore_fb_li.c b/src/lib/ecore_fb/ecore_fb_li.c
new file mode 100644
index 0000000000..0ea0549f92
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_li.c
@@ -0,0 +1,721 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore_Fb.h"
+#include "ecore_fb_private.h"
+
+#define CLICK_THRESHOLD_DEFAULT 0.25
+
+static Eina_List *_ecore_fb_li_devices = NULL;
+
+static const char *_ecore_fb_li_kbd_syms[128 * 7] =
+{
+#include "ecore_fb_keytable.h"
+};
+
+/* Initial Copyright (C) Brad Hards (1999-2002),
+ * this function is used to tell if "bit" is set in "array"
+ * it selects a byte from the array, and does a boolean AND
+ * operation with a byte that only has the relevant bit set.
+ * eg. to check for the 12th bit, we do (array[1] & 1<<4).
+ * Moved to static inline in order to force compiler to otimized
+ * the unsued part away or force a link error if long has an unexpected
+ * size.
+ * - bigeasy
+ */
+extern int long_has_neither_32_nor_64_bits(void);
+static inline int
+test_bit(int bit, unsigned long *array)
+{
+ if (sizeof(long) == 4)
+ return array[bit / 32] & (1 << (bit % 32));
+ else if (sizeof(long) == 8)
+ return array[bit / 64] & (1 << (bit % 64));
+ else long_has_neither_32_nor_64_bits();
+}
+
+static void
+_ecore_fb_li_device_event_key(Ecore_Fb_Input_Device *dev, struct input_event *iev)
+{
+ if (!dev->listen) return;
+
+ /* check for basic keyboard keys */
+ if ((iev->code >= KEY_ESC) && (iev->code <= KEY_COMPOSE))
+ {
+ int offset = 0;
+ const char *keyname = _ecore_fb_li_kbd_syms[iev->code * 7];
+
+ /* check the key table */
+ if (iev->value)
+ {
+ /* its a repeated key, dont increment */
+ if (iev->value != 2)
+ {
+ if (!strcmp(keyname, "Control_L"))
+ dev->keyboard.ctrl++;
+ else if (!strcmp(keyname, "Control_R"))
+ dev->keyboard.ctrl++;
+ else if (!strcmp(keyname, "Alt_L"))
+ dev->keyboard.alt++;
+ else if (!strcmp(keyname, "Alt_R"))
+ dev->keyboard.alt++;
+ else if (!strcmp(keyname, "Shift_L"))
+ dev->keyboard.shift++;
+ else if (!strcmp(keyname, "Shift_R"))
+ dev->keyboard.shift++;
+ else if (!strcmp(keyname, "Caps_Lock"))
+ dev->keyboard.lock = !dev->keyboard.lock;
+ if (dev->keyboard.ctrl > 2) dev->keyboard.ctrl = 2;
+ if (dev->keyboard.alt > 2) dev->keyboard.alt = 2;
+ if (dev->keyboard.shift > 2) dev->keyboard.shift = 2;
+ if (dev->keyboard.lock > 1) dev->keyboard.lock = 1;
+ }
+ }
+ else
+ {
+ if (!strcmp(keyname, "Control_L"))
+ dev->keyboard.ctrl--;
+ else if (!strcmp(keyname, "Control_R"))
+ dev->keyboard.ctrl--;
+ else if (!strcmp(keyname, "Alt_L"))
+ dev->keyboard.alt--;
+ else if (!strcmp(keyname, "Alt_R"))
+ dev->keyboard.alt--;
+ else if (!strcmp(keyname, "Shift_L"))
+ dev->keyboard.shift--;
+ else if (!strcmp(keyname, "Shift_R"))
+ dev->keyboard.shift--;
+ if (dev->keyboard.ctrl < 0) dev->keyboard.ctrl = 0;
+ if (dev->keyboard.alt < 0) dev->keyboard.alt = 0;
+ if (dev->keyboard.shift < 0) dev->keyboard.shift = 0;
+ if (dev->keyboard.lock < 0) dev->keyboard.lock = 0;
+ }
+
+ /* sending ecore_input_evas events */
+ Ecore_Event_Key *e;
+
+ if (dev->keyboard.shift) offset = 1;
+ else if (dev->keyboard.lock) offset = 2;
+
+ const char *key = _ecore_fb_li_kbd_syms[(iev->code * 7) + offset];
+ const char *compose = _ecore_fb_li_kbd_syms[(iev->code * 7) + 3 + offset];
+
+ if (dev->keyboard.ctrl)
+ {
+ const char *ts = _ecore_fb_li_kbd_syms[(iev->code * 7) + 3 + 3];
+
+ if (ts) compose = ts;
+ }
+
+ e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) +
+ strlen(keyname) + (compose ? strlen(compose) : 0) + 3);
+ e->keyname = (char *)(e + 1);
+ e->key = e->keyname + strlen(keyname) + 1;
+ e->compose = (compose) ? e->key + strlen(key) + 1 : NULL;
+ e->string = e->compose;
+
+ strcpy((char *)e->keyname, keyname);
+ strcpy((char *)e->key, key);
+ if (compose)
+ strcpy((char *)e->compose, compose);
+
+ e->modifiers = 0;
+ if (dev->keyboard.shift)
+ e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ e->window = (Ecore_Window)dev->window;
+ e->event_window = (Ecore_Window)dev->window;
+ e->root_window = (Ecore_Window)dev->window;
+ e->same_screen = 1;
+
+ if (iev->value)
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL);
+ else
+ ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
+ }
+ /* check for mouse button events */
+ else if ((iev->code >= BTN_MOUSE) && (iev->code < BTN_JOYSTICK))
+ {
+ int button;
+ Ecore_Event_Mouse_Button *e;
+ double current = ecore_loop_time_get();
+
+ button = ((iev->code & 0x00F) + 1);
+ // swap 2 and 3 to make middle and right butotn work right.
+ if (button == 3) button = 2;
+ else if (button == 2) button = 3;
+ if (iev->value)
+ {
+ dev->mouse.did_double = EINA_FALSE;
+ dev->mouse.did_triple = EINA_FALSE;
+
+ if (((current - dev->mouse.prev) <= dev->mouse.threshold) &&
+ (button == dev->mouse.prev_button))
+ {
+ dev->mouse.did_double = EINA_TRUE;
+ if (((current - dev->mouse.last) <= (2 * dev->mouse.threshold)) &&
+ (button == dev->mouse.last_button))
+ {
+ dev->mouse.did_triple = EINA_TRUE;
+ /* reset */
+ dev->mouse.prev = 0;
+ dev->mouse.last = 0;
+ current = 0;
+ }
+ }
+ dev->mouse.last = dev->mouse.prev;
+ dev->mouse.prev = current;
+ dev->mouse.last_button = dev->mouse.prev_button;
+ dev->mouse.prev_button = button;
+ }
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e)
+ return;
+
+ e->timestamp = current * 1000.0;
+ e->window = (Ecore_Window)dev->window;
+ e->event_window = (Ecore_Window)dev->window;
+ e->root_window = (Ecore_Window)dev->window;
+ e->same_screen = 1;
+
+ e->modifiers = 0;
+ if (dev->keyboard.shift)
+ e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ e->x = dev->mouse.x;
+ e->y = dev->mouse.y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->buttons = button;
+
+ if (dev->mouse.did_double)
+ e->double_click = 1;
+ if (dev->mouse.did_triple)
+ e->triple_click = 1;
+
+ if (iev->value)
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL);
+ else
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL);
+ }
+}
+
+static void
+_ecore_fb_li_device_event_rel(Ecore_Fb_Input_Device *dev, struct input_event *iev)
+{
+ if (!dev->listen) return;
+ /* dispatch the button events if they are queued */
+ switch (iev->code)
+ {
+ case REL_X:
+ case REL_Y:
+ {
+ Ecore_Event_Mouse_Move *e;
+ if (iev->code == REL_X)
+ {
+ dev->mouse.x += iev->value;
+ if (dev->mouse.x > dev->mouse.w - 1)
+ dev->mouse.x = dev->mouse.w;
+ else if(dev->mouse.x < 0)
+ dev->mouse.x = 0;
+ }
+ else
+ {
+ dev->mouse.y += iev->value;
+ if (dev->mouse.y > dev->mouse.h - 1)
+ dev->mouse.y = dev->mouse.h;
+ else if(dev->mouse.y < 0)
+ dev->mouse.y = 0;
+ }
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e)
+ return;
+
+ e->window = (Ecore_Window)dev->window;
+ e->event_window = (Ecore_Window)dev->window;
+ e->root_window = (Ecore_Window)dev->window;
+ e->same_screen = 1;
+
+ e->modifiers = 0;
+ if (dev->keyboard.shift) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ e->x = dev->mouse.x;
+ e->y = dev->mouse.y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+
+ break;
+ }
+ case REL_WHEEL:
+ case REL_HWHEEL:
+ {
+ Ecore_Event_Mouse_Wheel *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
+ if (!e)
+ return;
+
+ e->x = dev->mouse.x;
+ e->y = dev->mouse.y;
+ if (iev->code == REL_HWHEEL) e->direction = 1;
+ e->z = iev->value;
+ e->root.x = dev->mouse.x;
+ e->root.y = dev->mouse.y;
+
+ e->window = (Ecore_Window)dev->window;
+ e->event_window = (Ecore_Window)dev->window;
+ e->root_window = (Ecore_Window)dev->window;
+ e->same_screen = 1;
+
+ e->modifiers = 0;
+ if (dev->keyboard.shift) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL);
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+_ecore_fb_li_device_event_abs(Ecore_Fb_Input_Device *dev, struct input_event *iev)
+{
+ static int prev_pressure = 0;
+ int pressure;
+
+ if (!dev->listen) return;
+ switch (iev->code)
+ {
+ case ABS_X:
+ if (dev->mouse.w != 0)
+ {
+ int tmp;
+
+ tmp = (int)((double)(iev->value - dev->mouse.min_w) / dev->mouse.rel_w);
+ if (tmp < 0) dev->mouse.x = 0;
+ else if (tmp > dev->mouse.w) dev->mouse.x = dev->mouse.w;
+ else dev->mouse.x = tmp;
+ dev->mouse.event = ECORE_EVENT_MOUSE_MOVE;
+ }
+ break;
+
+ case ABS_Y:
+ if (dev->mouse.h != 0)
+ {
+ int tmp;
+
+ tmp = (int)((double)(iev->value - dev->mouse.min_h) / dev->mouse.rel_h);
+ if (tmp < 0) dev->mouse.y = 0;
+ else if (tmp > dev->mouse.h) dev->mouse.y = dev->mouse.h;
+ else dev->mouse.y = tmp;
+ dev->mouse.event = ECORE_EVENT_MOUSE_MOVE;
+ }
+ break;
+
+ case ABS_PRESSURE:
+ pressure = iev->value;
+ if ((pressure) && (!prev_pressure))
+ {
+ /* DOWN: mouse is down, but was not before */
+ dev->mouse.event = ECORE_EVENT_MOUSE_BUTTON_DOWN;
+ }
+ else if ((!pressure) && (prev_pressure))
+ {
+ /* UP: mouse was down, but is not now */
+ dev->mouse.event = ECORE_EVENT_MOUSE_BUTTON_UP;
+ }
+ prev_pressure = pressure;
+ break;
+ }
+}
+
+static void
+_ecore_fb_li_device_event_syn(Ecore_Fb_Input_Device *dev, struct input_event *iev EINA_UNUSED)
+{
+ if (!dev->listen) return;
+
+ if (dev->mouse.event == ECORE_EVENT_MOUSE_MOVE)
+ {
+ Ecore_Event_Mouse_Move *ev;
+ ev = calloc(1,sizeof(Ecore_Event_Mouse_Move));
+ ev->x = dev->mouse.x;
+ ev->y = dev->mouse.y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->timestamp = ecore_loop_time_get() * 1000.0;
+ }
+ else if (dev->mouse.event == ECORE_EVENT_MOUSE_BUTTON_DOWN)
+ {
+ Ecore_Event_Mouse_Button *ev;
+ ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ ev->x = dev->mouse.x;
+ ev->y = dev->mouse.y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->buttons = 1;
+ ev->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+ }
+ else if (dev->mouse.event == ECORE_EVENT_MOUSE_BUTTON_UP)
+ {
+ Ecore_Event_Mouse_Button *ev;
+ ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ ev->x = dev->mouse.x;
+ ev->y = dev->mouse.y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+ ev->buttons = 1;
+ ev->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+ }
+}
+
+static Eina_Bool
+_ecore_fb_li_device_fd_callback(void *data, Ecore_Fd_Handler *fdh EINA_UNUSED)
+{
+ Ecore_Fb_Input_Device *dev;
+ struct input_event ev[64];
+ int len;
+ int i;
+
+ dev = (Ecore_Fb_Input_Device*)data;
+ /* read up to 64 events at once */
+ len = read(dev->fd, &ev, sizeof(ev));
+ for(i = 0; i < (int)(len / sizeof(ev[0])); i++)
+ {
+ switch(ev[i].type)
+ {
+ case EV_SYN:
+ _ecore_fb_li_device_event_syn(dev, &ev[i]);
+ break;
+ case EV_ABS:
+ _ecore_fb_li_device_event_abs(dev, &ev[i]);
+ break;
+ case EV_REL:
+ _ecore_fb_li_device_event_rel(dev, &ev[i]);
+ break;
+ case EV_KEY:
+ _ecore_fb_li_device_event_key(dev, &ev[i]);
+ break;
+ default:
+ break;
+ }
+ }
+ return EINA_TRUE;
+}
+
+/**
+ * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
+ *
+ * @{
+ */
+
+/**
+ * @brief Set the listen mode for an input device .
+ *
+ * @param dev The device to set the mode of.
+ * @param listen @c EINA_FALSE to disable listening mode, @c EINA_TRUE to
+ * enable it.
+ *
+ * This function enables or disables listening on the input device @p dev.
+ * If @p listen is @c EINA_FALSE, listening mode is disabled, if it is
+ * @c EINA_TRUE, it is enabled.
+ */
+EAPI void
+ecore_fb_input_device_listen(Ecore_Fb_Input_Device *dev, Eina_Bool listen)
+{
+ if (!dev) return;
+ if ((listen && dev->listen) || (!listen && !dev->listen)) return;
+ if (listen)
+ {
+ /* if the device already had a handler */
+ if (!dev->handler)
+ dev->handler = ecore_main_fd_handler_add(dev->fd, ECORE_FD_READ, _ecore_fb_li_device_fd_callback, dev, NULL, NULL);
+
+ }
+ dev->listen = listen;
+}
+
+#ifndef EV_CNT
+# define EV_CNT (EV_MAX+1)
+#endif
+
+/**
+ * @brief Associates an input device with the given @ref Ecore_Evas_Group.
+ *
+ * @param dev The input being associated with an @ref Ecore_Evas_Group (not @c NULL).
+ * @param window The window which this input is being associated to.
+ * @c NULL will remove any previous association.
+ *
+ * Events generated by this device will have a pointer to @p window. If this @p
+ * window is registered with ecore_event_window_register() or
+ * ecore_evas_input_event_register(), respective evas events will be delivered
+ * by the ecore_input_evas system. An example can be seen in the following code:
+ *
+ * @code
+ * Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 800, 600, NULL);
+ *
+ * ecore_evas_input_event_register(ee);
+ *
+ * device = ecore_fb_input_device_open(device_path);
+ * if (device)
+ * ecore_fb_input_device_window_set(device, ee);
+ *
+ * @endcode
+ *
+ * On the previous code, all input captured on the mentioned device will be
+ * delivered to the @c Ecore_Evas @c ee.
+ *
+ * @since 1.1
+ */
+EAPI void
+ecore_fb_input_device_window_set(Ecore_Fb_Input_Device *dev, void *window)
+{
+ if (!dev) return;
+
+ dev->window = window;
+}
+
+/**
+ * @brief Open an input device.
+ *
+ * @param dev The device to open.
+ * @return The @ref Ecore_Fb_Input_Device object that has been opened.
+ *
+ * This function opens the input device named @p dev and returns the
+ * object for it, or returns @c NULL on failure.
+ */
+EAPI Ecore_Fb_Input_Device *
+ecore_fb_input_device_open(const char *dev)
+{
+ Ecore_Fb_Input_Device *device;
+ unsigned long event_type_bitmask[EV_CNT / 32 + 1];
+ int event_type;
+ int fd;
+
+ if (!dev) return NULL;
+ device = calloc(1, sizeof(Ecore_Fb_Input_Device));
+ if (!device) return NULL;
+
+ if ((fd = open(dev, O_RDONLY, O_NONBLOCK)) < 0)
+ {
+ fprintf(stderr, "[ecore_fb_li:device_open] %s %s", dev, strerror(errno));
+ goto error_open;
+ }
+ /* query capabilities */
+ if (ioctl(fd, EVIOCGBIT(0, EV_MAX), event_type_bitmask) < 0)
+ {
+ fprintf(stderr,"[ecore_fb_li:device_open] query capabilities %s %s", dev, strerror(errno));
+ goto error_caps;
+ }
+ /* query name */
+ device->info.name = calloc(256, sizeof(char));
+ if (ioctl(fd, EVIOCGNAME(sizeof(char) * 256), device->info.name) < 0)
+ {
+ fprintf(stderr, "[ecore_fb_li:device_open] get name %s %s", dev, strerror(errno));
+ strcpy(device->info.name, "Unknown");
+ }
+ device->fd = fd;
+ device->info.dev = strdup(dev);
+ /* common */
+ device->mouse.threshold = CLICK_THRESHOLD_DEFAULT;
+
+ /* set info */
+ for (event_type = 0; event_type < EV_MAX; event_type++)
+ {
+ if (!test_bit(event_type, event_type_bitmask))
+ continue;
+ switch (event_type)
+ {
+ case EV_SYN:
+ break;
+ case EV_KEY:
+ device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS;
+ break;
+ case EV_REL:
+ device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_RELATIVE;
+ break;
+ case EV_ABS:
+ device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE;
+ break;
+ case EV_MSC:
+ case EV_LED:
+ case EV_SND:
+ case EV_REP:
+ case EV_FF :
+ case EV_FF_STATUS:
+ case EV_PWR:
+ default:
+ break;
+ }
+ }
+
+ _ecore_fb_li_devices = eina_list_append(_ecore_fb_li_devices, device);
+ return device;
+
+error_caps:
+ close(fd);
+error_open:
+ free(device);
+ return NULL;
+}
+
+/**
+ * @brief Close the given device.
+ *
+ * @param dev The device to close
+ *
+ * This function closes the device @p dev. If @p dev is @c NULL, this
+ * function does nothing.
+ */
+EAPI void
+ecore_fb_input_device_close(Ecore_Fb_Input_Device *dev)
+{
+ if (!dev || dev->fd < 0) return;
+ /* close the fd */
+ close(dev->fd);
+ /* remove the element from the list */
+ _ecore_fb_li_devices = eina_list_remove(_ecore_fb_li_devices, dev);
+ free(dev);
+}
+
+
+/**
+ * @brief Set the axis size of the given device.
+ *
+ * @param dev The device to set the axis size to.
+ * @param w The width of the axis.
+ * @param h The height of the axis.
+ *
+ * This function sets set the width @p w and height @p h of the axis
+ * of device @p dev. If @p dev is a relative input device, a width and
+ * height must set for it. If its absolute set the ioctl correctly, if
+ * not, unsupported device.
+ */
+EAPI void
+ecore_fb_input_device_axis_size_set(Ecore_Fb_Input_Device *dev, int w, int h)
+{
+ if (!dev) return;
+ if ((w < 0) || (h < 0)) return;
+ /* FIXME
+ * this code is for a touchscreen device,
+ * make it configurable (ABSOLUTE | RELATIVE)
+ */
+ if (dev->info.cap & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE)
+ {
+ /* FIXME looks like some kernels dont include this struct */
+ struct input_absinfo abs_features;
+
+ ioctl(dev->fd, EVIOCGABS(ABS_X), &abs_features);
+ dev->mouse.min_w = abs_features.minimum;
+ dev->mouse.rel_w = (double)(abs_features.maximum - abs_features.minimum)/(double)(w);
+
+ ioctl(dev->fd, EVIOCGABS(ABS_Y), &abs_features);
+ dev->mouse.min_h = abs_features.minimum;
+ dev->mouse.rel_h = (double)(abs_features.maximum - abs_features.minimum)/(double)(h);
+ }
+ else if (!(dev->info.cap & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE))
+ return;
+
+ /* update the local values */
+ if (dev->mouse.x > w - 1) dev->mouse.x = w -1;
+ if (dev->mouse.y > h - 1) dev->mouse.y = h -1;
+ dev->mouse.w = w;
+ dev->mouse.h = h;
+}
+
+/**
+ * @brief Retrieve the name of the given device.
+ *
+ * @param dev The device to get the name from.
+ * @return The name of the device.
+ *
+ * This function returns the name of the device @p dev. If @p dev is
+ * @c NULL, this function returns @c NULL.
+ */
+EAPI const char *
+ecore_fb_input_device_name_get(Ecore_Fb_Input_Device *dev)
+{
+ if (!dev) return NULL;
+ return dev->info.name;
+}
+
+/**
+ * @brief Retrieve the capability of the given device.
+ *
+ * @param dev The device to get the name from.
+ * @return The capability of the device.
+ *
+ * This function returns the capability of the device @p dev. If @p dev is
+ * @c NULL, this function returns ECORE_FB_INPUT_DEVICE_CAP_NONE.
+ */
+EAPI Ecore_Fb_Input_Device_Cap
+ecore_fb_input_device_cap_get(Ecore_Fb_Input_Device *dev)
+{
+ if (!dev) return ECORE_FB_INPUT_DEVICE_CAP_NONE;
+ return dev->info.cap;
+}
+
+/**
+ * @brief Set the threshold of mouse clicks of the given device.
+ *
+ * @param dev The device to set the threshodl mouse click to.
+ * @param threshold The threshold value.
+ *
+ * This function sets the threshold of mouse clicks of the device
+ * @p dev to @p threshold. If @p dev is @c NULL, this function does
+ * nothing.
+ */
+EAPI void
+ecore_fb_input_device_threshold_click_set(Ecore_Fb_Input_Device *dev, double threshold)
+{
+ if (!dev) return;
+ if ((threshold == dev->mouse.threshold) || (threshold == 0)) return;
+ dev->mouse.threshold = threshold;
+}
+
+/**
+ * @brief Get the threshold of mouse clicks of the given device.
+ *
+ * @param dev The device to set the threshodl mouse click from.
+ * @return The threshold value.
+ *
+ * This function returns the threshold of mouse clicks of the device
+ * @p dev. If @p dev is @c NULL, this function returns 0.0.
+ */
+EAPI double
+ecore_fb_input_device_threshold_click_get(Ecore_Fb_Input_Device *dev)
+{
+ if (!dev) return 0;
+ return dev->mouse.threshold;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_fb/ecore_fb_private.h b/src/lib/ecore_fb/ecore_fb_private.h
new file mode 100644
index 0000000000..797f86305f
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_private.h
@@ -0,0 +1,94 @@
+#ifndef _ECORE_FB_PRIVATE_H
+#define _ECORE_FB_PRIVATE_H
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Input.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/version.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fb.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+ #define kernel_ulong_t unsigned long
+ #define BITS_PER_LONG 32
+ #include <linux/input.h>
+ #undef kernel_ulong_t
+ #undef BITS_PER_LONG
+#else
+ #include <linux/input.h>
+#endif
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <Ecore_Fb.h>
+
+/* ecore_fb_li.c */
+struct _Ecore_Fb_Input_Device
+{
+ int fd;
+ Ecore_Fd_Handler *handler;
+ int listen;
+ struct {
+ Ecore_Fb_Input_Device_Cap cap;
+ char *name;
+ char *dev;
+ } info;
+ struct
+ {
+ /* common mouse */
+ int x,y;
+ int w,h;
+
+ double last;
+ double prev;
+ double threshold;
+ Eina_Bool did_double;
+ Eina_Bool did_triple;
+ /* absolute axis */
+ int min_w, min_h;
+ double rel_w, rel_h;
+ int event;
+ int prev_button;
+ int last_button;
+ } mouse;
+ struct
+ {
+ int shift;
+ int ctrl;
+ int alt;
+ int lock;
+ } keyboard;
+ void *window;
+};
+
+/* ecore_fb_ts.c */
+EAPI int ecore_fb_ts_init(void);
+EAPI void ecore_fb_ts_shutdown(void);
+EAPI void ecore_fb_ts_events_window_set(void *window);
+EAPI void *ecore_fb_ts_events_window_get(void);
+EAPI void ecore_fb_ts_event_window_set(void *window);
+
+/* ecore_fb_vt.c */
+int ecore_fb_vt_init(void);
+void ecore_fb_vt_shutdown(void);
+
+/* hacks to stop people NEEDING #include <linux/h3600_ts.h> */
+#ifndef TS_SET_CAL
+#define TS_SET_CAL 0x4014660b
+#endif
+#ifndef TS_GET_CAL
+#define TS_GET_CAL 0x8014660a
+#endif
+
+#endif
diff --git a/src/lib/ecore_fb/ecore_fb_ps2.c b/src/lib/ecore_fb/ecore_fb_ps2.c
new file mode 100644
index 0000000000..53aa302fef
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_ps2.c
@@ -0,0 +1,223 @@
+typedef struct _Ecore_Fb_Ps2_Event Ecore_Fb_Ps2_Event;
+struct _Ecore_Fb_Ps2_Event
+{
+ unsigned char button;
+ unsigned char x;
+ unsigned char y;
+ unsigned char z;
+};
+
+static int _ecore_fb_ps2_event_byte_count = 0;
+static Ecore_Fb_Ps2_Event _ecore_fb_ps2_event;
+static int _ecore_fb_ps2_fd = 0;
+static Eina_Bool _ecore_fb_ps2_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
+
+int
+ecore_fb_ps2_init(void)
+{
+ _ecore_fb_ps2_fd = open("/dev/psaux", O_RDWR);
+ if (_ecore_fb_ps2_fd >= 0)
+ {
+ prev_flags = fcntl(_ecore_fb_ps2_fd, F_GETFL);
+ fcntl(_ecore_fb_ps2_fd, F_SETFL, prev_flags | O_NONBLOCK);
+ _ecore_fb_ts_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_ps2_fd,
+ ECORE_FD_READ,
+ _ecore_fb_ps2_fd_handler, NULL, NULL, NULL);
+ if (!_ecore_fb_ts_fd_handler_handle)
+ {
+ close(_ecore_fb_ps2_fd);
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void
+ecore_fb_ps2_shutdown(void)
+{
+ if (_ecore_fb_ps2_fd > 0) close(_ecore_fb_ps2_fd);
+ _ecore_fb_ps2_fd = 0;
+}
+
+static Eina_Bool
+_ecore_fb_ps2_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ static int prev_x = 0, prev_y = 0, prev_button = 0;
+ static double last_time = 0;
+ static double last_last_time = 0;
+ int v = 0;
+
+ do
+ {
+ int x, y, button, i;
+ int num;
+ char *ptr;
+ double t;
+ static int did_double = 0;
+ static int did_triple = 0;
+
+ ptr = (char *)&(_ecore_fb_ps2_event);
+ ptr += _ecore_fb_ps2_event_byte_count;
+ num = sizeof(Ecore_Fb_Ps2_Event) - _ecore_fb_ps2_event_byte_count;
+ v = read(_ecore_fb_ps2_fd, ptr, num);
+ if (v < 0) return EINA_TRUE;
+ _ecore_fb_ps2_event_byte_count += v;
+ if (v < num) return EINA_TRUE;
+ t = ecore_loop_time_get();
+ _ecore_fb_ps2_event_byte_count = 0;
+ if (_ecore_fb_ps2_event.button & 0x10)
+ x = prev_x + (0xffffff00 | _ecore_fb_ps2_event.x);
+ else
+ x = prev_x + _ecore_fb_ps2_event.x;
+ if (_ecore_fb_ps2_event.button & 0x20)
+ y = prev_y - (0xffffff00 | _ecore_fb_ps2_event.y);
+ else
+ y = prev_y - _ecore_fb_ps2_event.y;
+ button = _ecore_fb_ps2_event.button & 0x7;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (x >= _ecore_fb_console_w) x = _ecore_fb_console_w - 1;
+ if (y >= _ecore_fb_console_h) y = _ecore_fb_console_h - 1;
+ /* add event to queue */
+ /* always add a move event */
+ if (1)
+ {
+ /* MOVE: mouse is down and was */
+ Ecore_Event_Mouse_Move *e;
+
+ e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Move));
+ if (!e) goto retry;
+ e->x = x;
+ e->y = y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+ for (i = 1; i <= 3; i++)
+ {
+ int mask;
+
+ mask = 1 << (i - 1);
+ if (((button & mask)) && (!(prev_button & mask)))
+ {
+ /* DOWN: mouse is down, but was not now */
+ Ecore_Event_Mouse_Button *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) goto retry;
+ e->x = x;
+ e->y = y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->button = i;
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ if ((t - last_time) <= _ecore_fb_double_click_time)
+ {
+ e->double_click = 1;
+ did_double = 1;
+ }
+ else
+ {
+ did_double = 0;
+ did_triple = 0;
+ }
+ if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time))
+ {
+ did_triple = 1;
+ e->triple_click = 1;
+ }
+ else
+ {
+ did_triple = 0;
+ }
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL);
+ }
+ else if ((!(button & mask)) && ((prev_button & mask)))
+ {
+ /* UP: mouse was down, but is not now */
+ Ecore_Event_Mouse_Button *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) goto retry;
+ e->x = x;
+ e->y = y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->button = i;
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ if (did_double)
+ e->double_click = 1;
+ if (did_triple)
+ e->triple_click = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL);
+ }
+ }
+ if (did_triple)
+ {
+ last_time = 0;
+ last_last_time = 0;
+ }
+ else
+ {
+ last_last_time = last_time;
+ last_time = t;
+ }
+ retry:
+ prev_x = x;
+ prev_y = y;
+ prev_button = button;
+ }
+ while (v > 0);
+ return EINA_TRUE;
+}
+/**
+ * @defgroup Ecore_FB_Click_Group Framebuffer Double Click Functions
+ *
+ * Functions that deal with the double click time of the framebuffer.
+ */
+
+/**
+ * Sets the timeout for a double and triple clicks to be flagged.
+ *
+ * This sets the time between clicks before the double_click flag is
+ * set in a button down event. If 3 clicks occur within double this
+ * time, the triple_click flag is also set.
+ *
+ * @param t The time in seconds
+ * @ingroup Ecore_FB_Click_Group
+ */
+EAPI void
+ecore_fb_double_click_time_set(double t)
+{
+ if (t < 0.0) t = 0.0;
+ _ecore_fb_double_click_time = t;
+}
+
+/**
+ * Retrieves the double and triple click flag timeout.
+ *
+ * See @ref ecore_x_double_click_time_set for more information.
+ *
+ * @return The timeout for double clicks in seconds.
+ * @ingroup Ecore_FB_Click_Group
+ */
+EAPI double
+ecore_fb_double_click_time_get(void)
+{
+ return _ecore_fb_double_click_time;
+}
+
diff --git a/src/lib/ecore_fb/ecore_fb_ts.c b/src/lib/ecore_fb/ecore_fb_ts.c
new file mode 100644
index 0000000000..ce9c733c3e
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_ts.c
@@ -0,0 +1,362 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_TSLIB
+# include <tslib.h>
+# include <errno.h>
+#endif
+
+#include "Ecore_Fb.h"
+#include "ecore_fb_private.h"
+
+typedef struct _Ecore_Fb_Ts_Event Ecore_Fb_Ts_Event;
+typedef struct _Ecore_Fb_Ts_Calibrate Ecore_Fb_Ts_Calibrate;
+typedef struct _Ecore_Fb_Ts_Backlight Ecore_Fb_Ts_Backlight;
+typedef struct _Ecore_Fb_Ts_Contrast Ecore_Fb_Ts_Contrast;
+typedef struct _Ecore_Fb_Ts_Led Ecore_Fb_Ts_Led;
+typedef struct _Ecore_Fb_Ts_Flite Ecore_Fb_Ts_Flite;
+
+struct _Ecore_Fb_Ts_Event
+{
+ unsigned short pressure;
+ unsigned short x;
+ unsigned short y;
+ unsigned short _unused;
+};
+
+struct _Ecore_Fb_Ts_Calibrate
+{
+ int xscale;
+ int xtrans;
+ int yscale;
+ int ytrans;
+ int xyswap;
+};
+
+struct _Ecore_Fb_Ts_Backlight
+{
+ int on;
+ unsigned char brightness;
+};
+
+struct _Ecore_Fb_Ts_Contrast
+{
+ unsigned char contrast;
+};
+
+struct _Ecore_Fb_Ts_Led
+{
+ unsigned char on;
+ unsigned char blink_time;
+ unsigned char on_time;
+ unsigned char off_time;
+};
+
+struct _Ecore_Fb_Ts_Flite
+{
+ unsigned char mode;
+ unsigned char pwr;
+ unsigned char brightness;
+};
+
+static Eina_Bool _ecore_fb_ts_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
+static int _ecore_fb_ts_fd = -1;
+static int _ecore_fb_ts_event_byte_count = 0;
+static int _ecore_fb_ts_apply_cal = 0;
+static Ecore_Fb_Ts_Event _ecore_fb_ts_event;
+static Ecore_Fb_Ts_Calibrate _ecore_fb_ts_cal = {1,1,0,0,0};
+static Ecore_Fd_Handler *_ecore_fb_ts_fd_handler_handle = NULL;
+
+#ifdef HAVE_TSLIB
+struct tsdev *_ecore_fb_tslib_tsdev = NULL;
+struct ts_sample _ecore_fb_tslib_event;
+#endif
+
+static double _ecore_fb_double_click_time = 0.25;
+static void *_ecore_fb_ts_event_window = NULL;
+
+EAPI int
+ecore_fb_ts_init(void)
+{
+#ifdef HAVE_TSLIB
+ char *tslib_tsdevice = NULL;
+ if ( (tslib_tsdevice = getenv("TSLIB_TSDEVICE")) )
+ {
+ printf( "ECORE_FB: TSLIB_TSDEVICE = '%s'\n", tslib_tsdevice );
+ _ecore_fb_tslib_tsdev = ts_open( tslib_tsdevice, 1 ); /* 1 = nonblocking, 0 = blocking */
+
+ if ( !_ecore_fb_tslib_tsdev )
+ {
+ printf( "ECORE_FB: Can't ts_open (%s)\n", strerror( errno ) );
+ return 0;
+ }
+
+ if ( ts_config( _ecore_fb_tslib_tsdev ) )
+ {
+ printf( "ECORE_FB: Can't ts_config (%s)\n", strerror( errno ) );
+ return 0;
+ }
+ _ecore_fb_ts_fd = ts_fd( _ecore_fb_tslib_tsdev );
+ if ( _ecore_fb_ts_fd < 0 )
+ {
+ printf( "ECORE_FB: Can't open touchscreen (%s)\n", strerror( errno ) );
+ return 0;
+ }
+ }
+#else
+ _ecore_fb_ts_fd = open("/dev/touchscreen/0", O_RDONLY);
+#endif
+ if (_ecore_fb_ts_fd >= 0)
+ {
+ _ecore_fb_ts_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_ts_fd,
+ ECORE_FD_READ,
+ _ecore_fb_ts_fd_handler, NULL,
+ NULL, NULL);
+ if (!_ecore_fb_ts_fd_handler_handle)
+ {
+ close(_ecore_fb_ts_fd);
+ return 0;
+ }
+ // FIXME _ecore_fb_kbd_fd = open("/dev/touchscreen/key", O_RDONLY);
+ return 1;
+ }
+ return 0;
+}
+
+EAPI void
+ecore_fb_ts_shutdown(void)
+{
+ if (_ecore_fb_ts_fd_handler_handle)
+ ecore_main_fd_handler_del(_ecore_fb_ts_fd_handler_handle);
+ if (_ecore_fb_ts_fd >= 0) close(_ecore_fb_ts_fd);
+ _ecore_fb_ts_fd = -1;
+ _ecore_fb_ts_fd_handler_handle = NULL;
+ _ecore_fb_ts_event_window = NULL;
+}
+
+EAPI void
+ecore_fb_ts_event_window_set(void *window)
+{
+ _ecore_fb_ts_event_window = window;
+}
+
+EAPI void *
+ecore_fb_ts_event_window_get(void)
+{
+ return _ecore_fb_ts_event_window;
+}
+
+/**
+ * @defgroup Ecore_FB_Calibrate_Group Framebuffer Calibration Functions
+ *
+ * Functions that calibrate the screen.
+ */
+
+
+/**
+ * Calibrates the touschreen using the given parameters.
+ * @param xscale X scaling, where 256 = 1.0
+ * @param xtrans X translation.
+ * @param yscale Y scaling.
+ * @param ytrans Y translation.
+ * @param xyswap Swap X & Y flag.
+ * @ingroup Ecore_FB_Calibrate_Group
+ */
+EAPI void
+ecore_fb_touch_screen_calibrate_set(int xscale, int xtrans, int yscale, int ytrans, int xyswap)
+{
+ Ecore_Fb_Ts_Calibrate cal;
+
+ if (_ecore_fb_ts_fd < 0) return;
+ cal.xscale = xscale;
+ cal.xtrans = xtrans;
+ cal.yscale = yscale;
+ cal.ytrans = ytrans;
+ cal.xyswap = xyswap;
+ if (ioctl(_ecore_fb_ts_fd, TS_SET_CAL, (void *)&cal))
+ {
+ _ecore_fb_ts_cal = cal;
+ _ecore_fb_ts_apply_cal = 1;
+ }
+}
+
+/**
+ * Retrieves the calibration parameters of the touchscreen.
+ * @param xscale Pointer to an integer in which to store the X scaling.
+ * Note that 256 = 1.0.
+ * @param xtrans Pointer to an integer in which to store the X translation.
+ * @param yscale Pointer to an integer in which to store the Y scaling.
+ * @param ytrans Pointer to an integer in which to store the Y translation.
+ * @param xyswap Pointer to an integer in which to store the Swap X & Y flag.
+ * @ingroup Ecore_FB_Calibrate_Group
+ */
+EAPI void
+ecore_fb_touch_screen_calibrate_get(int *xscale, int *xtrans, int *yscale, int *ytrans, int *xyswap)
+{
+ Ecore_Fb_Ts_Calibrate cal;
+
+ if (_ecore_fb_ts_fd < 0) return;
+ if (!_ecore_fb_ts_apply_cal)
+ {
+ if (ioctl(_ecore_fb_ts_fd, TS_GET_CAL, (void *)&cal))
+ _ecore_fb_ts_cal = cal;
+ }
+ else
+ cal = _ecore_fb_ts_cal;
+ if (xscale) *xscale = cal.xscale;
+ if (xtrans) *xtrans = cal.xtrans;
+ if (yscale) *yscale = cal.yscale;
+ if (ytrans) *ytrans = cal.ytrans;
+ if (xyswap) *xyswap = cal.xyswap;
+}
+
+static Eina_Bool
+_ecore_fb_ts_fd_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ static int prev_x = 0, prev_y = 0, prev_pressure = 0;
+ static double last_time = 0;
+ static double last_last_time = 0;
+ int v = 0;
+
+ do
+ {
+ int x, y, pressure;
+ int num;
+ char *ptr;
+ double t = 0.0;
+ static int did_double = 0;
+ static int did_triple = 0;
+
+#ifdef HAVE_TSLIB
+ if (_ecore_fb_ts_apply_cal)
+ num = ts_read_raw(_ecore_fb_tslib_tsdev, &_ecore_fb_tslib_event, 1);
+ else
+ num = ts_read(_ecore_fb_tslib_tsdev, &_ecore_fb_tslib_event, 1);
+ if (num != 1) return 1; /* no more samples at this time */
+ x = _ecore_fb_tslib_event.x;
+ y = _ecore_fb_tslib_event.y;
+ pressure = _ecore_fb_tslib_event.pressure;
+ v = 1; /* loop, there might be more samples */
+#else
+ ptr = (char *)&(_ecore_fb_ts_event);
+ ptr += _ecore_fb_ts_event_byte_count;
+ num = sizeof(Ecore_Fb_Ts_Event) - _ecore_fb_ts_event_byte_count;
+ v = read(_ecore_fb_ts_fd, ptr, num);
+ if (v < 0) return 1;
+ _ecore_fb_ts_event_byte_count += v;
+ if (v < num) return 1;
+ _ecore_fb_ts_event_byte_count = 0;
+ if (_ecore_fb_ts_apply_cal)
+ {
+ x = ((_ecore_fb_ts_cal.xscale * _ecore_fb_ts_event.x) >> 8) + _ecore_fb_ts_cal.xtrans;
+ y = ((_ecore_fb_ts_cal.yscale * _ecore_fb_ts_event.y) >> 8) + _ecore_fb_ts_cal.ytrans;
+ }
+ else
+ {
+ x = _ecore_fb_ts_event.x;
+ y = _ecore_fb_ts_event.y;
+ }
+ pressure = _ecore_fb_ts_event.pressure;
+#endif
+ t = ecore_loop_time_get();
+ /* add event to queue */
+ /* always add a move event */
+ if ((pressure) || (prev_pressure))
+ {
+ /* MOVE: mouse is down and was */
+ Ecore_Event_Mouse_Move *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) goto retry;
+ e->x = x;
+ e->y = y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+ if ((pressure) && (!prev_pressure))
+ {
+ /* DOWN: mouse is down, but was not now */
+ Ecore_Event_Mouse_Button *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) goto retry;
+ e->x = x;
+ e->y = y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->buttons = 1;
+ if ((t - last_time) <= _ecore_fb_double_click_time)
+ {
+ e->double_click = 1;
+ did_double = 1;
+ }
+ else
+ {
+ did_double = 0;
+ did_triple = 0;
+ }
+ if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time))
+ {
+ did_triple = 1;
+ e->triple_click = 1;
+ }
+ else
+ {
+ did_triple = 0;
+ }
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL);
+ }
+ else if ((!pressure) && (prev_pressure))
+ {
+ /* UP: mouse was down, but is not now */
+ Ecore_Event_Mouse_Button *e;
+
+ e = calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) goto retry;
+ e->x = prev_x;
+ e->y = prev_y;
+ e->root.x = e->x;
+ e->root.y = e->y;
+ e->buttons = 1;
+ if (did_double)
+ e->double_click = 1;
+ if (did_triple)
+ e->triple_click = 1;
+ e->window = 1;
+ e->event_window = e->window;
+ e->root_window = e->window;
+ e->same_screen = 1;
+ e->timestamp = ecore_loop_time_get() * 1000.0;
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL);
+ }
+ if (did_triple)
+ {
+ last_time = 0;
+ last_last_time = 0;
+ }
+ else
+ {
+ last_last_time = last_time;
+ last_time = t;
+ }
+retry:
+ prev_x = x;
+ prev_y = y;
+ prev_pressure = pressure;
+ }
+ while (v > 0);
+ return 1;
+}
+
diff --git a/src/lib/ecore_fb/ecore_fb_vt.c b/src/lib/ecore_fb/ecore_fb_vt.c
new file mode 100644
index 0000000000..c92c087336
--- /dev/null
+++ b/src/lib/ecore_fb/ecore_fb_vt.c
@@ -0,0 +1,322 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Ecore_Fb.h"
+#include "ecore_fb_private.h"
+
+static int _ecore_fb_vt_do_switch = 0;
+
+static int _ecore_fb_vt_tty0_fd = -1;
+static int _ecore_fb_vt_tty_fd = -1;
+static int _ecore_fb_vt_current_vt = 0;
+static int _ecore_fb_vt_prev_vt = 0;
+
+static struct termios _ecore_fb_tty_prev_tio_mode;
+static struct vt_mode _ecore_fb_vt_prev_mode;
+
+static Eina_Bool _ecore_fb_signal_usr_handler(void *data, int type, void *ev);
+static Ecore_Event_Handler *_ecore_fb_user_handler = NULL;
+static int _ecore_fb_tty_prev_mode = 0;
+static int _ecore_fb_tty_prev_kd_mode = 0;
+
+/* callbacks for an attach/release of a vt */
+static void (*_ecore_fb_func_fb_lost) (void *data) = NULL;
+static void *_ecore_fb_func_fb_lost_data = NULL;
+static void (*_ecore_fb_func_fb_gain) (void *data) = NULL;
+static void *_ecore_fb_func_fb_gain_data = NULL;
+
+/* FIXME what is the filter for? */
+static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL;
+
+/* prototypes */
+/* XXX: unused
+static void _ecore_fb_vt_switch(int vt);
+static void *_ecore_fb_event_filter_start(void *data);
+static Eina_Bool _ecore_fb_event_filter_filter(void *data, void *loop_data, int type, void *event);
+static void _ecore_fb_event_filter_end(void *data, void *loop_data);
+*/
+
+static Eina_Bool
+_ecore_fb_signal_usr_handler(void *data EINA_UNUSED, int type EINA_UNUSED, void *ev)
+{
+ Ecore_Event_Signal_User *e;
+
+ e = (Ecore_Event_Signal_User *)ev;
+ if (e->number == 1)
+ {
+ /* release vt */
+ if (_ecore_fb_func_fb_lost) _ecore_fb_func_fb_lost(_ecore_fb_func_fb_lost_data);
+ /* TODO stop listening from the devices? let the callback do it? */
+ ioctl(_ecore_fb_vt_tty_fd, VT_RELDISP, 1);
+ }
+ else if (e->number == 2)
+ {
+ /* attach vt */
+ if (_ecore_fb_func_fb_gain) _ecore_fb_func_fb_gain(_ecore_fb_func_fb_gain_data);
+ /* TODO reattach all devices */
+ }
+ return 1;
+}
+
+/* XXX: unused
+static void
+_ecore_fb_vt_switch(int vt)
+{
+ vt++;
+ if (_ecore_fb_vt_tty_fd != 0)
+ {
+ if (vt != _ecore_fb_vt_current_vt)
+ {
+ tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
+ ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
+ ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
+ }
+ }
+ ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt);
+}
+*/
+
+static int
+_ecore_fb_vt_setup(void)
+{
+ char buf[64];
+// XXX: unused
+// struct termios tio;
+ struct vt_mode new_vtmode;
+
+ if (_ecore_fb_vt_current_vt != _ecore_fb_vt_prev_vt)
+ {
+ snprintf(buf, sizeof(buf), "/dev/tty%i", _ecore_fb_vt_current_vt);
+ if ((_ecore_fb_vt_tty_fd = open(buf, O_RDWR)) < 0)
+ {
+ printf("[ecore_fb:vt_setup] can't open tty %d\n", _ecore_fb_vt_current_vt);
+ return 0;
+ }
+ close(_ecore_fb_vt_tty0_fd);
+ _ecore_fb_vt_tty0_fd = -1;
+ /* FIXME detach the process from current tty ? */
+ }
+ else
+ _ecore_fb_vt_tty_fd = _ecore_fb_vt_tty0_fd;
+ /* for backup */
+ tcgetattr(_ecore_fb_vt_tty_fd, &_ecore_fb_tty_prev_tio_mode);
+ ioctl(_ecore_fb_vt_tty_fd, KDGETMODE, &_ecore_fb_tty_prev_kd_mode);
+ ioctl(_ecore_fb_vt_tty_fd, VT_GETMODE, &_ecore_fb_vt_prev_mode);
+
+ if (ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, KD_GRAPHICS) < 0)
+ {
+ perror("[ecore_fb:vt_setup] can't set the mode to KD_GRAPHICS");
+ close(_ecore_fb_vt_tty_fd);
+ _ecore_fb_vt_tty_fd = -1;
+ return 0;
+ }
+ ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode);
+
+ /* support of switching */
+ new_vtmode.mode = VT_PROCESS;
+ new_vtmode.waitv = 0;
+ new_vtmode.relsig = SIGUSR1;
+ new_vtmode.acqsig = SIGUSR2;
+ if (ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &new_vtmode) < 0)
+ {
+ perror("[ecore_fb:vt_setup] can't set the tty mode");
+ close(_ecore_fb_vt_tty_fd);
+ _ecore_fb_vt_tty_fd = -1;
+ return 0;
+ }
+ /* register signal handlers when alloc/detach of vt */
+ _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
+ _ecore_fb_signal_usr_handler,
+ NULL);
+ /* What does this do? */
+ /*
+ _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL);
+ */
+
+ usleep(40000);
+ if (ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0)
+ {
+ perror("[ecore_fb:vt_setup] error on VT_ACTIVATE");
+ close(_ecore_fb_vt_tty_fd);
+ _ecore_fb_vt_tty_fd = -1;
+ return 0;
+ }
+ if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0)
+ {
+ perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE");
+ close(_ecore_fb_vt_tty_fd);
+ _ecore_fb_vt_tty_fd = -1;
+ return 0;
+ }
+ /* FIXME assign the fb to the tty in case isn't setup */
+ return 1;
+}
+
+int
+ecore_fb_vt_init(void)
+{
+ struct vt_stat vtstat;
+
+ /* as root you can allocate another tty */
+ if (!geteuid())
+ _ecore_fb_vt_do_switch = 1;
+ if ((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0)
+ {
+ printf("[ecore_fb:init] can't open /dev/tty0\n");
+ return 0;
+ }
+ /* query current vt state */
+ if ((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0)
+ {
+ printf("[ecore_fb:init] can't get current tty state\n");
+ return 0;
+ }
+ _ecore_fb_vt_prev_vt = vtstat.v_active;
+ /* switch to another tty */
+ if (_ecore_fb_vt_do_switch)
+ {
+ int vtno;
+
+ if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0))
+ {
+ printf("[ecore_fb:init] can't query for a vt\n");
+ return 0;
+ }
+ _ecore_fb_vt_current_vt = vtno;
+ }
+ /* use current tty */
+ else
+ _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt;
+ if (!_ecore_fb_vt_setup())
+ {
+ printf("[ecore_fb:init] can't setup the vt, restoring previous mode...\n");
+ /* TODO finish this */
+ if (_ecore_fb_vt_do_switch)
+ {
+ printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+void
+ecore_fb_vt_shutdown(void)
+{
+ /* restore the previous mode */
+ if (_ecore_fb_vt_tty_fd != -1)
+ {
+ tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode);
+ ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode);
+ ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode);
+ ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode);
+ /* go back to previous vt */
+ close(_ecore_fb_vt_tty_fd);
+ _ecore_fb_vt_tty_fd = -1;
+ }
+
+ if (_ecore_fb_user_handler) ecore_event_handler_del(_ecore_fb_user_handler);
+ _ecore_fb_user_handler = NULL;
+
+ if (_ecore_fb_filter_handler) ecore_event_filter_del(_ecore_fb_filter_handler);
+ _ecore_fb_filter_handler = NULL;
+}
+
+/**
+ * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions.
+ *
+ * @{
+ */
+
+/**
+ * @brief Set a callback called when a virtual terminal is gained.
+ *
+ * @param func The callback called when vt is gained.
+ * @param data The data to pass to the callback.
+ *
+ * This function sets the callback @p func which will be called when a
+ * virtual terminal is gained (for example you press Ctrl-Alt-F1 to go
+ * to vt1 and your app was using vt1). @p data will be pass to @p func if
+ * the callback is called.
+ */
+EAPI void
+ecore_fb_callback_gain_set(void (*func) (void *data), void *data)
+{
+ _ecore_fb_func_fb_gain = func;
+ _ecore_fb_func_fb_gain_data = data;
+}
+
+/**
+ * @brief Set a callback called when a virtual terminal is lost.
+ *
+ * @param func The callback called when vt is lost.
+ * @param data The data to pass to the callback.
+ *
+ * This function sets the callback @p func which will be called when a
+ * virtual terminal is lost (someone wants the tv from you and you
+ * want to give up that vt). @p data will be pass to @p func if the
+ * callback is called.
+ */
+EAPI void
+ecore_fb_callback_lose_set(void (*func) (void *data), void *data)
+{
+ _ecore_fb_func_fb_lost = func;
+ _ecore_fb_func_fb_lost_data = data;
+
+}
+
+/**
+ * @}
+ */
+
+/*
+ * This filter should take into account that the MOUSE_MOVE event can be
+ * triggered by a mouse, not just a touchscreen device, so you can't discard
+ * them (only those generated by a device that sends events with absolute
+ * coordinates).
+
+typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data;
+
+struct _Ecore_Fb_Filter_Data
+{
+ int last_event_type;
+};
+
+static void *
+_ecore_fb_event_filter_start(void *data EINA_UNUSED)
+{
+ Ecore_Fb_Filter_Data *filter_data;
+
+ filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data));
+ return filter_data;
+}
+
+static Eina_Bool
+_ecore_fb_event_filter_filter(void *data EINA_UNUSED, void *loop_data,int type, void *event EINA_UNUSED)
+{
+ Ecore_Fb_Filter_Data *filter_data;
+
+ filter_data = loop_data;
+ if (!filter_data) return EINA_TRUE;
+ if (type == ECORE_EVENT_MOUSE_MOVE)
+ {
+ if ((filter_data->last_event_type) == ECORE_EVENT_MOUSE_MOVE)
+ {
+ filter_data->last_event_type = type;
+ return EINA_FALSE;
+ }
+ }
+ filter_data->last_event_type = type;
+ return EINA_TRUE;
+}
+
+static void
+_ecore_fb_event_filter_end(void *data EINA_UNUSED, void *loop_data)
+{
+ Ecore_Fb_Filter_Data *filter_data;
+
+ filter_data = loop_data;
+ if (filter_data) free(filter_data);
+}
+*/
diff --git a/src/lib/ecore_file/Ecore_File.h b/src/lib/ecore_file/Ecore_File.h
new file mode 100644
index 0000000000..30f3bd7d9e
--- /dev/null
+++ b/src/lib/ecore_file/Ecore_File.h
@@ -0,0 +1,190 @@
+#ifndef ECORE_FILE_H
+#define ECORE_FILE_H
+
+/*
+ * TODO:
+ * - More events, move/rename of directory file
+ */
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_FILE_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_FILE_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore_File.h
+ * @brief Files utility functions
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_File_Group Ecore_File - Files and directories convenience functions
+ *
+ * @{
+ */
+
+/**
+ * @typedef Ecore_File_Monitor
+ * Abstract type used when monitoring a directory.
+ */
+typedef struct _Ecore_File_Monitor Ecore_File_Monitor;
+
+/**
+ * @typedef Ecore_File_Download_Job
+ * Abstract type used when aborting a download.
+ */
+typedef struct _Ecore_File_Download_Job Ecore_File_Download_Job;
+
+/**
+ * @typedef _Ecore_File_Event
+ * The event type returned when a file or directory is monitored.
+ */
+typedef enum _Ecore_File_Event
+{
+ ECORE_FILE_EVENT_NONE, /**< No event. */
+ ECORE_FILE_EVENT_CREATED_FILE, /**< Created file event. */
+ ECORE_FILE_EVENT_CREATED_DIRECTORY, /**< Created directory event. */
+ ECORE_FILE_EVENT_DELETED_FILE, /**< Deleted file event. */
+ ECORE_FILE_EVENT_DELETED_DIRECTORY, /**< Deleted directory event. */
+ ECORE_FILE_EVENT_DELETED_SELF, /**< Deleted monitored directory event. */
+ ECORE_FILE_EVENT_MODIFIED, /**< Modified file or directory event. */
+ ECORE_FILE_EVENT_CLOSED /**< Closed file event */
+} Ecore_File_Event;
+
+/**
+ * @typedef Ecore_File_Monitor_Cb
+ * Callback type used when a monitored directory has changes.
+ */
+typedef void (*Ecore_File_Monitor_Cb)(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path);
+
+/**
+ * @typedef Ecore_File_Download_Completion_Cb
+ * Callback type used when a download is finished.
+ */
+typedef void (*Ecore_File_Download_Completion_Cb)(void *data, const char *file, int status);
+
+/**
+ * @typedef _Ecore_File_Progress_Return
+ * What to do with the download as a return from the
+ * Ecore_File_Download_Progress_Cb function, if provided.
+ */
+typedef enum _Ecore_File_Progress_Return
+{
+ ECORE_FILE_PROGRESS_CONTINUE = 0, /**< Continue the download. */
+ ECORE_FILE_PROGRESS_ABORT = 1 /**< Abort the download. */
+} Ecore_File_Progress_Return;
+
+/**
+ * @typedef Ecore_File_Download_Progress_Cb
+ * Callback type used while a download is in progress.
+ */
+typedef int (*Ecore_File_Download_Progress_Cb)(void *data,
+ const char *file,
+ long int dltotal,
+ long int dlnow,
+ long int ultotal,
+ long int ulnow);
+
+/* File operations */
+
+EAPI int ecore_file_init (void);
+EAPI int ecore_file_shutdown (void);
+EAPI long long ecore_file_mod_time (const char *file);
+EAPI long long ecore_file_size (const char *file);
+EAPI Eina_Bool ecore_file_exists (const char *file);
+EAPI Eina_Bool ecore_file_is_dir (const char *file);
+EAPI Eina_Bool ecore_file_mkdir (const char *dir);
+EAPI int ecore_file_mkdirs (const char **dirs);
+EAPI int ecore_file_mksubdirs (const char *base, const char **subdirs);
+EAPI Eina_Bool ecore_file_rmdir (const char *dir);
+EAPI Eina_Bool ecore_file_recursive_rm (const char *dir);
+EAPI Eina_Bool ecore_file_mkpath (const char *path);
+EAPI int ecore_file_mkpaths (const char **paths);
+EAPI Eina_Bool ecore_file_cp (const char *src, const char *dst);
+EAPI Eina_Bool ecore_file_mv (const char *src, const char *dst);
+EAPI Eina_Bool ecore_file_symlink (const char *src, const char *dest);
+EAPI char *ecore_file_realpath (const char *file);
+EAPI Eina_Bool ecore_file_unlink (const char *file);
+EAPI Eina_Bool ecore_file_remove (const char *file);
+EAPI const char *ecore_file_file_get (const char *path);
+EAPI char *ecore_file_dir_get (const char *path);
+EAPI Eina_Bool ecore_file_can_read (const char *file);
+EAPI Eina_Bool ecore_file_can_write (const char *file);
+EAPI Eina_Bool ecore_file_can_exec (const char *file);
+EAPI char *ecore_file_readlink (const char *link);
+EAPI Eina_List *ecore_file_ls (const char *dir);
+EAPI Eina_Iterator *ecore_file_ls_iterator (const char *dir);
+EAPI char *ecore_file_app_exe_get (const char *app);
+EAPI char *ecore_file_escape_name (const char *filename);
+EAPI char *ecore_file_strip_ext (const char *file);
+EAPI int ecore_file_dir_is_empty (const char *dir);
+
+/* Monitoring */
+
+EAPI Ecore_File_Monitor *ecore_file_monitor_add(const char *path,
+ Ecore_File_Monitor_Cb func,
+ void *data);
+EAPI void ecore_file_monitor_del(Ecore_File_Monitor *ecore_file_monitor);
+EAPI const char *ecore_file_monitor_path_get(Ecore_File_Monitor *ecore_file_monitor);
+
+/* Path */
+
+EAPI Eina_Bool ecore_file_path_dir_exists(const char *in_dir);
+EAPI Eina_Bool ecore_file_app_installed(const char *exe);
+EAPI Eina_List *ecore_file_app_list(void);
+
+/* Download */
+
+EAPI Eina_Bool ecore_file_download(const char *url,
+ const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Ecore_File_Download_Job **job_ret);
+EAPI Eina_Bool ecore_file_download_full(const char *url,
+ const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Ecore_File_Download_Job **job_ret,
+ Eina_Hash *headers);
+
+EAPI void ecore_file_download_abort_all(void);
+EAPI void ecore_file_download_abort(Ecore_File_Download_Job *job);
+EAPI Eina_Bool ecore_file_download_protocol_available(const char *protocol);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_file/ecore_file.c b/src/lib/ecore_file/ecore_file.c
new file mode 100644
index 0000000000..6876511fc6
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file.c
@@ -0,0 +1,1137 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+# include <libgen.h>
+#endif
+
+#ifdef _WIN32
+# include <direct.h>
+#endif
+
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_ATFILE_SOURCE
+# include <dirent.h>
+#endif
+
+#include "ecore_file_private.h"
+
+int _ecore_file_log_dom = -1;
+static int _ecore_file_init_count = 0;
+
+/* externally accessible functions */
+
+/**
+ * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize the Ecore_File library.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up Ecore_File and the services it will use
+ * (monitoring, downloading, PATH related feature). It returns 0 on
+ * failure, otherwise it returns the number of times it has already
+ * been called.
+ *
+ * When Ecore_File is not used anymore, call ecore_file_shutdown()
+ * to shut down the Ecore_File library.
+ */
+EAPI int
+ecore_file_init()
+{
+ if (++_ecore_file_init_count != 1)
+ return _ecore_file_init_count;
+
+ if (!ecore_init())
+ return --_ecore_file_init_count;
+
+ _ecore_file_log_dom = eina_log_domain_register
+ ("ecore_file", ECORE_FILE_DEFAULT_LOG_COLOR);
+ if(_ecore_file_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the ecore file module.");
+ return --_ecore_file_init_count;
+ }
+ ecore_file_path_init();
+ ecore_file_monitor_init();
+ ecore_file_download_init();
+
+ /* FIXME: were the tests disabled for a good reason ? */
+
+ /*
+ if (!ecore_file_monitor_init())
+ goto shutdown_ecore_file_path;
+
+ if (!ecore_file_download_init())
+ goto shutdown_ecore_file_monitor;
+ */
+
+ return _ecore_file_init_count;
+
+ /*
+ shutdown_ecore_file_monitor:
+ ecore_file_monitor_shutdown();
+ shutdown_ecore_file_path:
+ ecore_file_path_shutdown();
+
+ return --_ecore_file_init_count;
+ */
+}
+
+/**
+ * @brief Shut down the Ecore_File library.
+ *
+ * @return 0 when the library is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Ecore_File library. It returns 0 when it has
+ * been called the same number of times than ecore_file_init(). In that case
+ * it shuts down all the services it uses.
+ */
+EAPI int
+ecore_file_shutdown()
+{
+ if (--_ecore_file_init_count != 0)
+ return _ecore_file_init_count;
+
+ ecore_file_download_shutdown();
+ ecore_file_monitor_shutdown();
+ ecore_file_path_shutdown();
+
+ eina_log_domain_unregister(_ecore_file_log_dom);
+ _ecore_file_log_dom = -1;
+
+ ecore_shutdown();
+
+ return _ecore_file_init_count;
+}
+
+/**
+ * @brief Get the time of the last modification to the given file.
+ *
+ * @param file The name of the file.
+ * @return Return the time of the last data modification, or 0 on
+ * failure.
+ *
+ * This function returns the time of the last modification of
+ * @p file. On failure, it returns 0.
+ */
+EAPI long long
+ecore_file_mod_time(const char *file)
+{
+ struct stat st;
+
+ if (stat(file, &st) < 0) return 0;
+ return st.st_mtime;
+}
+
+/**
+ * @brief Get the size of the given file.
+ *
+ * @param file The name of the file.
+ * @return Return the size of the file in bytes, or 0 on failure.
+ *
+ * This function returns the size of @p file in bytes. On failure, it
+ * returns 0.
+ */
+EAPI long long
+ecore_file_size(const char *file)
+{
+ struct stat st;
+
+ if (stat(file, &st) < 0) return 0;
+ return st.st_size;
+}
+
+/**
+ * @brief Check if the given file exists.
+ *
+ * @param file The name of the file.
+ * @return @c EINA_TRUE if the @p file exists, @c EINA_FALSE otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p file exists on local filesystem,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_exists(const char *file)
+{
+ struct stat st;
+ if (!file) return EINA_FALSE;
+
+ /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/
+ if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Check if the given file is a directory.
+ *
+ * @param file The name of the file.
+ * @return @c EINA_TRUE if the file exists and is a directory, @c EINA_FALSE
+ * otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p file exists exists and is a
+ * directory on local filesystem, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_is_dir(const char *file)
+{
+ struct stat st;
+
+ if (stat(file, &st) < 0) return EINA_FALSE;
+ if (S_ISDIR(st.st_mode)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+
+/**
+ * @brief Create a new directory.
+ *
+ * @param dir The name of the directory to create
+ * @return @c EINA_TRUE on successful creation, @c EINA_FALSE otherwise.
+ *
+ * This function creates the directory @p dir with the mode S_IRUSR |
+ * S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH. On
+ * success, it returns @c EINA_TRUE, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_mkdir(const char *dir)
+{
+ if (mkdir(dir, default_mode) < 0) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Create complete directory in a batch.
+ *
+ * @param dirs The list of directories, null terminated.
+ * @return The number of successful directories created, -1 if dirs is
+ * @c NULL.
+ *
+ * This function creates all the directories that are in the null
+ * terminated array @p dirs. The function loops over the directories
+ * and call ecore_file_mkdir(). This function returns -1 if @p dirs is
+ * @c NULL, otherwise if returns the number of suceesfully created
+ * directories.
+ */
+EAPI int
+ecore_file_mkdirs(const char **dirs)
+{
+ int i = 0;
+
+ if (!dirs) return -1;
+
+ for (; *dirs; dirs++)
+ if (ecore_file_mkdir(*dirs))
+ i++;
+ return i;
+}
+
+/**
+ * @brief Create complete list of sub-directories in a batch (optimized).
+ *
+ * @param base The base directory to act on.
+ * @param subdirs The list of directories, null terminated.
+ * @return number of successful directories created, -1 on failure.
+ *
+ * This function creates all the directories that are in the null
+ * terminated array @p dirs in the @p base directory. If @p base does
+ * not exist, it will be created. The function loops over the directories
+ * and call ecore_file_mkdir(). The whole path of the directories must
+ * exist. So if base/a/b/c wants to be created, @p subdirs must
+ * contain "a", "a/b" and "a/b/c", in that order. This function
+ * returns -1 if @p dirs or @p base are @c NULL, or if @p base is
+ * empty ("\0"). It returns 0 is @p base is not a directory or
+ * invalid, or if it can't be created. Otherwise if returns the number
+ * of suceesfully created directories.
+ */
+EAPI int
+ecore_file_mksubdirs(const char *base, const char **subdirs)
+{
+#ifndef HAVE_ATFILE_SOURCE
+ char buf[PATH_MAX];
+ int baselen;
+#else
+ int fd;
+ DIR *dir;
+#endif
+ int i;
+
+ if (!subdirs) return -1;
+ if ((!base) || (base[0] == '\0')) return -1;
+
+ if ((!ecore_file_is_dir(base)) && (!ecore_file_mkpath(base)))
+ return 0;
+
+#ifndef HAVE_ATFILE_SOURCE
+ baselen = eina_strlcpy(buf, base, sizeof(buf));
+ if ((baselen < 1) || (baselen + 1 >= (int)sizeof(buf)))
+ return 0;
+
+ if (buf[baselen - 1] != '/')
+ {
+ buf[baselen] = '/';
+ baselen++;
+ }
+#else
+ dir = opendir(base);
+ if (!dir)
+ return 0;
+ fd = dirfd(dir);
+#endif
+
+ i = 0;
+ for (; *subdirs; subdirs++)
+ {
+ struct stat st;
+
+#ifndef HAVE_ATFILE_SOURCE
+ eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen);
+ if (stat(buf, &st) == 0)
+#else
+ if (fstatat(fd, *subdirs, &st, 0) == 0)
+#endif
+ {
+ if (S_ISDIR(st.st_mode))
+ {
+ i++;
+ continue;
+ }
+ }
+ else
+ {
+ if (errno == ENOENT)
+ {
+#ifndef HAVE_ATFILE_SOURCE
+ if (mkdir(buf, default_mode) == 0)
+#else
+ if (mkdirat(fd, *subdirs, default_mode) == 0)
+#endif
+ {
+ i++;
+ continue;
+ }
+ }
+ }
+ }
+
+#ifdef HAVE_ATFILE_SOURCE
+ closedir(dir);
+#endif
+
+ return i;
+}
+
+/**
+ * @brief Delete the given directory.
+ *
+ * @param dir The name of the directory to delete.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function deletes @p dir. It returns @c EINA_TRUE on success,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_rmdir(const char *dir)
+{
+ if (rmdir(dir) < 0) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Delete the given file.
+ *
+ * @param file The name of the file to delete.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function deletes @p file. It returns @c EINA_TRUE on success,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_unlink(const char *file)
+{
+ if (unlink(file) < 0) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Remove the given file or directory.
+ *
+ * @param file The name of the file or directory to delete.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function removes @p file. It returns @c EINA_TRUE on success,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_remove(const char *file)
+{
+ if (remove(file) < 0) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Delete the given directory and all its contents.
+ *
+ * @param dir The name of the directory to delete.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function delete @p dir and all its contents. If @p dir is a
+ * link only the link is removed. It returns @c EINA_TRUE on success,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_recursive_rm(const char *dir)
+{
+ struct stat st;
+
+#ifdef _WIN32
+ char buf[PATH_MAX];
+
+ if (readlink(dir, buf, sizeof(buf) - 1) > 0)
+ return ecore_file_unlink(dir);
+ if (stat(dir, &st) == -1)
+ return EINA_FALSE;
+#else
+ if (lstat(dir, &st) == -1)
+ return EINA_FALSE;
+#endif
+
+ if (S_ISDIR(st.st_mode))
+ {
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *it;
+ int ret;
+
+ ret = 1;
+ it = eina_file_direct_ls(dir);
+ EINA_ITERATOR_FOREACH(it, info)
+ {
+ if (!ecore_file_recursive_rm(info->path))
+ ret = 0;
+ }
+ eina_iterator_free(it);
+
+ if (!ecore_file_rmdir(dir)) ret = 0;
+ if (ret)
+ return EINA_TRUE;
+ else
+ return EINA_FALSE;
+ }
+ else
+ {
+ return ecore_file_unlink(dir);
+ }
+}
+
+static inline Eina_Bool
+_ecore_file_mkpath_if_not_exists(const char *path)
+{
+ struct stat st;
+
+ /* Windows: path like C: or D: etc are valid, but stat() returns an error */
+#ifdef _WIN32
+ if ((strlen(path) == 2) &&
+ ((path[0] >= 'a' && path[0] <= 'z') ||
+ (path[0] >= 'A' && path[0] <= 'Z')) &&
+ (path[1] == ':'))
+ return EINA_TRUE;
+#endif
+
+ if (stat(path, &st) < 0)
+ return ecore_file_mkdir(path);
+ else if (!S_ISDIR(st.st_mode))
+ return EINA_FALSE;
+ else
+ return EINA_TRUE;
+}
+
+/**
+ * @brief Create a complete path.
+ *
+ * @param path The path to create
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function creates @p path and all the subdirectories it
+ * contains. The separator is '/' or '\'. If @p path exists, this
+ * function returns @c EINA_TRUE immediately. It returns @c EINA_TRUE on
+ * success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_mkpath(const char *path)
+{
+ char ss[PATH_MAX];
+ unsigned int i;
+
+ if (ecore_file_is_dir(path))
+ return EINA_TRUE;
+
+ for (i = 0; path[i] != '\0'; ss[i] = path[i], i++)
+ {
+ if (i == sizeof(ss) - 1) return EINA_FALSE;
+ if (((path[i] == '/') || (path[i] == '\\')) && (i > 0))
+ {
+ ss[i] = '\0';
+ if (!_ecore_file_mkpath_if_not_exists(ss))
+ return EINA_FALSE;
+ }
+ }
+ ss[i] = '\0';
+ return _ecore_file_mkpath_if_not_exists(ss);
+}
+
+/**
+ * @brief Create complete paths in a batch.
+ *
+ * @param paths list of paths, null terminated.
+ * @return number of successful paths created, -1 if paths is NULL.
+ *
+ * This function creates all the directories that are in the null
+ * terminated array @p paths. The function loops over the directories
+ * and call ecore_file_mkpath(), hence on Windows, '\' must be
+ * replaced by '/' before calling that function. This function
+ * returns -1 if @p paths is @c NULL. Otherwise if returns the number
+ * of suceesfully created directories.
+ */
+EAPI int
+ecore_file_mkpaths(const char **paths)
+{
+ int i = 0;
+
+ if (!paths) return -1;
+
+ for (; *paths; paths++)
+ if (ecore_file_mkpath(*paths))
+ i++;
+ return i;
+}
+
+/**
+ * @brief Copy the given file to the given destination.
+ *
+ * @param src The name of the source file.
+ * @param dst The name of the destination file.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function copies @p src to @p dst. If the absolute path name of
+ * @p src and @p dst can not be computed, or if they are equal, or if
+ * the copy fails, the function returns @c EINA_FALSE, otherwise it
+ * returns @c EINA_TRUE.
+ */
+EAPI Eina_Bool
+ecore_file_cp(const char *src, const char *dst)
+{
+ FILE *f1, *f2;
+ char buf[16384];
+ char realpath1[PATH_MAX], realpath2[PATH_MAX];
+ size_t num;
+ Eina_Bool ret = EINA_TRUE;
+
+ if (!realpath(src, realpath1)) return EINA_FALSE;
+ if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE;
+
+ f1 = fopen(src, "rb");
+ if (!f1) return EINA_FALSE;
+ f2 = fopen(dst, "wb");
+ if (!f2)
+ {
+ fclose(f1);
+ return EINA_FALSE;
+ }
+ while ((num = fread(buf, 1, sizeof(buf), f1)) > 0)
+ {
+ if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE;
+ }
+ fclose(f1);
+ fclose(f2);
+ return ret;
+}
+
+/**
+ * @brief Move the given file to the given destination.
+ *
+ * @param src The name of the source file.
+ * @param dst The name of the destination file.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function moves @p src to @p dst. It returns @c EINA_TRUE on
+ * success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_mv(const char *src, const char *dst)
+{
+ char buf[PATH_MAX];
+ int fd;
+
+ if (rename(src, dst))
+ {
+ // File cannot be moved directly because
+ // it resides on a different mount point.
+ if (errno == EXDEV)
+ {
+ struct stat st;
+
+ // Make sure this is a regular file before
+ // we do anything fancy.
+ stat(src, &st);
+ if (S_ISREG(st.st_mode))
+ {
+ char *dir;
+
+ dir = ecore_file_dir_get(dst);
+ // Since we can't directly rename, try to
+ // copy to temp file in the dst directory
+ // and then rename.
+ snprintf(buf, sizeof(buf), "%s/.%s.tmp.XXXXXX",
+ dir, ecore_file_file_get(dst));
+ free(dir);
+ fd = mkstemp(buf);
+ if (fd < 0) goto FAIL;
+ close(fd);
+
+ // Copy to temp file
+ if (!ecore_file_cp(src, buf))
+ goto FAIL;
+
+ // Set file permissions of temp file to match src
+ chmod(buf, st.st_mode);
+
+ // Try to atomically move temp file to dst
+ if (rename(buf, dst))
+ {
+ // If we still cannot atomically move
+ // do a normal copy and hope for the best.
+ if (!ecore_file_cp(buf, dst))
+ goto FAIL;
+ }
+
+ // Delete temporary file and src
+ ecore_file_unlink(buf);
+ ecore_file_unlink(src);
+ goto PASS;
+ }
+ }
+ goto FAIL;
+ }
+
+PASS:
+ return EINA_TRUE;
+
+FAIL:
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Create a symbolic link.
+ *
+ * @param src The name of the file to link.
+ * @param dest The name of link.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function create the symbolic link @p dest of @p src. This
+ * function does not work on Windows. It returns @c EINA_TRUE on success,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_symlink(const char *src, const char *dest)
+{
+ if (!symlink(src, dest)) return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Get the canonicalized absolute path name.
+ *
+ * @param file The file path.
+ * @return The canonicalized absolute pathname or an empty string on
+ * failure.
+ *
+ * This function returns the absolute path name of @p file as a newly
+ * allocated string. If @p file is @c NULL, or on error, this function
+ * returns an empty string. Otherwise, it returns the absolute path
+ * name. When not needed anymore, the returned value must be freed.
+ */
+EAPI char *
+ecore_file_realpath(const char *file)
+{
+ char buf[PATH_MAX];
+
+ /*
+ * Some implementations of realpath do not conform to the SUS.
+ * And as a result we must prevent a null arg from being passed.
+ */
+ if (!file) return strdup("");
+ if (!realpath(file, buf)) return strdup("");
+
+ return strdup(buf);
+}
+
+/**
+ * Get the filename from a given path.
+ *
+ * @param path The complete path.
+ * @return The file name.
+ *
+ * This function returns the file name of @p path. If @p path is
+ * @c NULL, the functions returns @c NULL.
+ */
+EAPI const char *
+ecore_file_file_get(const char *path)
+{
+ char *result = NULL;
+
+ if (!path) return NULL;
+ if ((result = strrchr(path, '/'))) result++;
+ else result = (char *)path;
+ return result;
+}
+
+/**
+ * @brief Get the directory where the given file resides.
+ *
+ * @param file The name of the file.
+ * @return The directory name.
+ *
+ * This function returns the directory where @p file resides as anewly
+ * allocated string. If @p file is @c NULL or on error, this function
+ * returns @c NULL. When not needed anymore, the returned value must
+ * be freed.
+ */
+EAPI char *
+ecore_file_dir_get(const char *file)
+{
+ char *p;
+ char buf[PATH_MAX];
+
+ if (!file) return NULL;
+ strncpy(buf, file, PATH_MAX);
+ buf[PATH_MAX - 1] = 0;
+ p = dirname(buf);
+ return strdup(p);
+}
+
+/**
+ * @brief Check if the given file can be read.
+ *
+ * @param file The name of the file.
+ * @return @c EINA_TRUE if the @p file is readable, @c EINA_FALSE otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p file can be read, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_can_read(const char *file)
+{
+ if (!file) return EINA_FALSE;
+ if (!access(file, R_OK)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given file can be written.
+ *
+ * @param file The name of the file.
+ * @return @c EINA_TRUE if the @p file is writable, @c EINA_FALSE otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p file can be written, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_can_write(const char *file)
+{
+ if (!file) return EINA_FALSE;
+ if (!access(file, W_OK)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given file can be executed.
+ *
+ * @param file The name of the file.
+ * @return @c EINA_TRUE if the @p file can be executed, @c EINA_FALSE
+ * otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p file can be executed, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_can_exec(const char *file)
+{
+ if (!file) return EINA_FALSE;
+ if (!access(file, X_OK)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Get the path pointed by the given link.
+ *
+ * @param lnk The name of the link.
+ * @return The path pointed by link or NULL.
+ *
+ * This function returns the path pointed by @p link as a newly
+ * allocated string. This function does not work on Windows. On
+ * failure, the function returns @c NULL. When not needed anymore, the
+ * returned value must be freed.
+ */
+EAPI char *
+ecore_file_readlink(const char *lnk)
+{
+ char buf[PATH_MAX];
+ int count;
+
+ if ((count = readlink(lnk, buf, sizeof(buf) - 1)) < 0) return NULL;
+ buf[count] = 0;
+ return strdup(buf);
+}
+
+/**
+ * @brief Get the list of the files and directories in the given
+ * directory.
+ *
+ * @param dir The name of the directory to list
+ * @return Return an Eina_List containing all the files in the directory;
+ * on failure it returns NULL.
+ *
+ * This function returns a list of allocated strings of all the files
+ * and directories contained in @p dir. The list will be sorted with
+ * strcoll as compare function. That means that you may want to set
+ * the current locale for the category LC_COLLATE with
+ * setlocale(). For more information see the manual pages of strcoll
+ * and setlocale. The list will not contain the directory entries for
+ * '.' and '..'. On failure, @c NULL is returned. When not needed
+ * anymore, the list elements must be freed.
+ */
+EAPI Eina_List *
+ecore_file_ls(const char *dir)
+{
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *ls;
+ Eina_List *list = NULL;
+
+ ls = eina_file_direct_ls(dir);
+ if (!ls) return NULL;
+
+ EINA_ITERATOR_FOREACH(ls, info)
+ {
+ char *f;
+
+ f = strdup(info->path + info->name_start);
+ list = eina_list_append(list, f);
+ }
+ eina_iterator_free(ls);
+
+ list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll));
+
+ return list;
+}
+
+/**
+ * @brief Return the executable from the given command.
+ *
+ * @param app The application command, with parameters.
+ * @return The executable from @p app as a newly allocated string. Arguments
+ * are removed and escape characters are handled. If @p app is @c NULL, or
+ * on failure, the function returns @c NULL. When not needed anymore, the
+ * returned value must be freed.
+ */
+EAPI char *
+ecore_file_app_exe_get(const char *app)
+{
+ char *p, *pp, *exe1 = NULL, *exe2 = NULL;
+ char *exe = NULL;
+ int in_quot_dbl = 0, in_quot_sing = 0, restart = 0;
+
+ if (!app) return NULL;
+
+ p = (char *)app;
+restart:
+ while ((*p) && (isspace((unsigned char)*p))) p++;
+ exe1 = p;
+ while (*p)
+ {
+ if (in_quot_sing)
+ {
+ if (*p == '\'')
+ in_quot_sing = 0;
+ }
+ else if (in_quot_dbl)
+ {
+ if (*p == '\"')
+ in_quot_dbl = 0;
+ }
+ else
+ {
+ if (*p == '\'')
+ in_quot_sing = 1;
+ else if (*p == '\"')
+ in_quot_dbl = 1;
+ if ((isspace((unsigned char)*p)) && ((p <= app) || (p[-1] == '\\')))
+ break;
+ }
+ p++;
+ }
+ exe2 = p;
+ if (exe2 == exe1) return NULL;
+ if (*exe1 == '~')
+ {
+ char *homedir;
+ int len;
+
+ /* Skip ~ */
+ exe1++;
+
+ homedir = getenv("HOME");
+ if (!homedir) return NULL;
+ len = strlen(homedir);
+ if (exe) free(exe);
+ exe = malloc(len + exe2 - exe1 + 2);
+ if (!exe) return NULL;
+ pp = exe;
+ if (len)
+ {
+ strcpy(exe, homedir);
+ pp += len;
+ if (*(pp - 1) != '/')
+ {
+ *pp = '/';
+ pp++;
+ }
+ }
+ }
+ else
+ {
+ if (exe) free(exe);
+ exe = malloc(exe2 - exe1 + 1);
+ if (!exe) return NULL;
+ pp = exe;
+ }
+ p = exe1;
+ restart = 0;
+ in_quot_dbl = 0;
+ in_quot_sing = 0;
+ while (*p)
+ {
+ if (in_quot_sing)
+ {
+ if (*p == '\'')
+ in_quot_sing = 0;
+ else
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+ else if (in_quot_dbl)
+ {
+ if (*p == '\"')
+ in_quot_dbl = 0;
+ else
+ {
+ /* technically this is wrong. double quotes also accept
+ * special chars:
+ *
+ * $, `, \
+ */
+ *pp = *p;
+ pp++;
+ }
+ }
+ else
+ {
+ /* technically we should handle special chars:
+ *
+ * $, `, \, etc.
+ */
+ if ((p > exe1) && (p[-1] == '\\'))
+ {
+ if (*p != '\n')
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+ else if ((p > exe1) && (*p == '='))
+ {
+ restart = 1;
+ *pp = *p;
+ pp++;
+ }
+ else if (*p == '\'')
+ in_quot_sing = 1;
+ else if (*p == '\"')
+ in_quot_dbl = 1;
+ else if (isspace((unsigned char)*p))
+ {
+ if (restart)
+ goto restart;
+ else
+ break;
+ }
+ else
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+ p++;
+ }
+ *pp = 0;
+ return exe;
+}
+
+/**
+ * @brief Add the escape sequence ('\\') to the given file name.
+ *
+ * @param filename The file name.
+ * @return The file name with special characters escaped.
+ *
+ * This function adds the escape sequence ('\\') to the given file
+ * name and returns the result as a newly allocated string. If the
+ * length of the returned string is longer than PATH_MAX, or on
+ * failure, @c NULL is returned. When not needed anymore, the returned
+ * value must be freed.
+ */
+EAPI char *
+ecore_file_escape_name(const char *filename)
+{
+ const char *p;
+ char *q;
+ char buf[PATH_MAX];
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+
+ p = filename;
+ q = buf;
+ while (*p)
+ {
+ if ((q - buf) > (PATH_MAX - 6)) return NULL;
+ if (
+ (*p == ' ') || (*p == '\\') || (*p == '\'') ||
+ (*p == '\"') || (*p == ';') || (*p == '!') ||
+ (*p == '#') || (*p == '$') || (*p == '%') ||
+ (*p == '&') || (*p == '*') || (*p == '(') ||
+ (*p == ')') || (*p == '[') || (*p == ']') ||
+ (*p == '{') || (*p == '}') || (*p == '|') ||
+ (*p == '<') || (*p == '>') || (*p == '?')
+ )
+ {
+ *q = '\\';
+ q++;
+ }
+ else if (*p == '\t')
+ {
+ *q = '\\';
+ q++;
+ *q = '\\';
+ q++;
+ *q = 't';
+ q++;
+ p++;
+ continue;
+ }
+ else if (*p == '\n')
+ {
+ *q = '\\';
+ q++;
+ *q = '\\';
+ q++;
+ *q = 'n';
+ q++;
+ p++;
+ continue;
+ }
+
+ *q = *p;
+ q++;
+ p++;
+ }
+ *q = 0;
+ return strdup(buf);
+}
+
+/**
+ * @brief Remove the extension from the given file name.
+ *
+ * @param path The name of the file.
+ * @return A newly allocated string with the extension stripped out or
+ * @c NULL on errors.
+ *
+ * This function removes the extension from @p path and returns the
+ * result as a newly allocated string. If @p path is @c NULL, or on
+ * failure, the function returns @c NULL. When not needed anymore, the
+ * returned value must be freed.
+ */
+EAPI char *
+ecore_file_strip_ext(const char *path)
+{
+ char *p, *file = NULL;
+
+ if (!path)
+ return NULL;
+
+ p = strrchr(path, '.');
+ if (!p)
+ file = strdup(path);
+ else if (p != path)
+ {
+ file = malloc(((p - path) + 1) * sizeof(char));
+ if (file)
+ {
+ memcpy(file, path, (p - path));
+ file[p - path] = 0;
+ }
+ }
+
+ return file;
+}
+
+/**
+ * @brief Check if the given directory is empty.
+ *
+ * @param dir The name of the directory to check.
+ * @return @c 1 if directory is empty, @c 0 if it has at least one file or
+ * @c -1 in case of errors.
+ *
+ * This functions checks if @p dir is empty. The '.' and '..' files
+ * will be ignored. If @p dir is empty, 1 is returned, if it contains
+ * at least one file, @c 0 is returned. On failure, @c -1 is returned.
+ */
+EAPI int
+ecore_file_dir_is_empty(const char *dir)
+{
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *it;
+
+ it = eina_file_direct_ls(dir);
+ if (!it) return -1;
+
+ EINA_ITERATOR_FOREACH(it, info)
+ {
+ eina_iterator_free(it);
+ return 0;
+ }
+
+ eina_iterator_free(it);
+ return 1;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_file/ecore_file_download.c b/src/lib/ecore_file/ecore_file_download.c
new file mode 100644
index 0000000000..98d4a1f972
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_download.c
@@ -0,0 +1,455 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef BUILD_ECORE_CON
+# include "Ecore_Con.h"
+#endif
+
+#include "ecore_file_private.h"
+
+#ifdef BUILD_ECORE_CON
+
+#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8
+#define ECORE_FILE_DOWNLOAD_TIMEOUT 30
+
+struct _Ecore_File_Download_Job
+{
+ ECORE_MAGIC;
+
+ Ecore_Con_Url *url_con;
+ FILE *file;
+
+ char *dst;
+
+ Ecore_File_Download_Completion_Cb completion_cb;
+ Ecore_File_Download_Progress_Cb progress_cb;
+};
+
+#ifdef HAVE_CURL
+Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Eina_Hash *headers);
+
+static Eina_Bool _ecore_file_download_url_complete_cb(void *data, int type, void *event);
+static Eina_Bool _ecore_file_download_url_progress_cb(void *data, int type, void *event);
+#endif
+
+static Ecore_Event_Handler *_url_complete_handler = NULL;
+static Ecore_Event_Handler *_url_progress_download = NULL;
+static Eina_List *_job_list;
+
+static int download_init = 0;
+
+#endif /* BUILD_ECORE_CON */
+
+int
+ecore_file_download_init(void)
+{
+#ifdef BUILD_ECORE_CON
+ download_init++;
+ if (download_init > 1) return 1;
+ if (!ecore_con_init()) return 0;
+ if (!ecore_con_url_init())
+ {
+ ecore_con_shutdown();
+ return 0;
+ }
+# ifdef HAVE_CURL
+ _url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL);
+ _url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL);
+# endif
+#endif /* BUILD_ECORE_CON */
+ return 1;
+}
+
+void
+ecore_file_download_shutdown(void)
+{
+#ifdef BUILD_ECORE_CON
+ download_init--;
+ if (download_init > 0) return;
+ if (_url_complete_handler)
+ ecore_event_handler_del(_url_complete_handler);
+ if (_url_progress_download)
+ ecore_event_handler_del(_url_progress_download);
+ _url_complete_handler = NULL;
+ _url_progress_download = NULL;
+ ecore_file_download_abort_all();
+ ecore_con_url_shutdown();
+ ecore_con_shutdown();
+#endif /* BUILD_ECORE_CON */
+}
+
+#ifdef BUILD_ECORE_CON
+# ifdef HAVE_CURL
+static Eina_Bool
+_ecore_file_download_headers_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata)
+{
+ Ecore_File_Download_Job *job = fdata;
+ ecore_con_url_additional_header_add(job->url_con, key, data);
+
+ return EINA_TRUE;
+}
+# endif
+#endif
+
+static Eina_Bool
+_ecore_file_download(const char *url,
+ const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Ecore_File_Download_Job **job_ret,
+ Eina_Hash *headers)
+{
+#ifdef BUILD_ECORE_CON
+ if (!url)
+ {
+ CRIT("Download URL is null");
+ return EINA_FALSE;
+ }
+
+ char *dir = ecore_file_dir_get(dst);
+
+ if (!ecore_file_is_dir(dir))
+ {
+ ERR("%s is not a directory", dir);
+ free(dir);
+ return EINA_FALSE;
+ }
+ free(dir);
+ if (ecore_file_exists(dst))
+ {
+ WRN("%s already exists", dst);
+ return EINA_FALSE;
+ }
+
+ if (!strncmp(url, "file://", 7))
+ {
+ /* FIXME: Maybe fork? Might take a while to copy.
+ * Check filesize? */
+ /* Just copy it */
+
+ url += 7;
+ /* skip hostname */
+ url = strchr(url, '/');
+ return ecore_file_cp(url, dst);
+ }
+# ifdef HAVE_CURL
+ else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
+ (!strncmp(url, "ftp://", 6)))
+ {
+ /* download */
+ Ecore_File_Download_Job *job;
+
+ job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data, headers);
+ if(job_ret) *job_ret = job;
+ if(job)
+ return EINA_TRUE;
+ else
+ {
+ ERR("no job returned\n");
+ return EINA_FALSE;
+ }
+ return job ? EINA_TRUE : EINA_FALSE;
+ }
+# else
+ else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
+ (!strncmp(url, "ftp://", 6)))
+ {
+ (void)completion_cb;
+ (void)progress_cb;
+ (void)data;
+ (void)job_ret;
+ (void)headers;
+ return EINA_FALSE;
+ }
+# endif
+ else
+ {
+ return EINA_FALSE;
+ }
+#else
+ (void)url;
+ (void)dst;
+ (void)completion_cb;
+ (void)progress_cb;
+ (void)data;
+ (void)job_ret;
+ (void)headers;
+ return EINA_FALSE;
+#endif /* BUILD_ECORE_CON */
+}
+
+/**
+ * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
+ *
+ * @{
+ */
+
+/**
+ * @brief Download the given url to the given destination.
+ *
+ * @param url The complete url to download.
+ * @param dst The local file to save the downloaded to.
+ * @param completion_cb A callback called on download complete.
+ * @param progress_cb A callback called during the download operation.
+ * @param data User data passed to both callbacks.
+ * @param job_ret Job used to abort the download.
+ * @return @c EINA_TRUE if the download start or @c EINA_FALSE on failure.
+ *
+ * This function starts the download of the URL @p url and saves it to
+ * @p dst. @p url must provide the protocol, including 'http://',
+ * 'ftp://' or 'file://'. Ecore_File must be compiled with CURL to
+ * download using http and ftp protocols. If @p dst is ill-formed, or
+ * if it already exists, the function returns @c EINA_FALSE. When the
+ * download is complete, the callback @p completion_cb is called and
+ * @p data is passed to it. The @p status parameter of @p completion_cb
+ * will be filled with the status of the download (200, 404,...). The
+ * @p progress_cb is called during the download operation, each time a
+ * packet is received or when CURL wants. It can be used to display the
+ * percentage of the downloaded file. Return 0 from this callback, if provided,
+ * to continue the operation or anything else to abort the download. The only
+ * operations that can be aborted are those with protocol 'http' or 'ftp'. In
+ * that case @p job_ret can be filled. It can be used with
+ * ecore_file_download_abort() or ecore_file_download_abort_all() to
+ * respectively abort one or all download operations. This function returns
+ * @c EINA_TRUE if the download starts, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_file_download(const char *url,
+ const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Ecore_File_Download_Job **job_ret)
+{
+ return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, NULL);
+}
+
+/**
+ * @brief Download the given url to the given destination with additional headers.
+ *
+ * @param url The complete url to download.
+ * @param dst The local file to save the downloaded to.
+ * @param completion_cb A callback called on download complete.
+ * @param progress_cb A callback called during the download operation.
+ * @param data User data passed to both callbacks.
+ * @param job_ret Job used to abort the download.
+ * @param headers pointer of header lists.
+ * @return @c EINA_TRUE if the download start or @c EINA_FALSE on failure.
+ */
+EAPI Eina_Bool
+ecore_file_download_full(const char *url,
+ const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Ecore_File_Download_Job **job_ret,
+ Eina_Hash *headers)
+{
+ return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, headers);
+}
+
+/**
+ * @brief Check if the given protocol is available.
+ *
+ * @param protocol The protocol to check.
+ * @return @c EINA_TRUE if protocol is handled, @c EINA_FALSE otherwise.
+ *
+ * This function returns @c EINA_TRUE if @p protocol is supported,
+ * @c EINA_FALSE otherwise. @p protocol can be 'http://', 'ftp://' or
+ * 'file://'. Ecore_FILE must be compiled with CURL to handle http and
+ * ftp protocols.
+ */
+EAPI Eina_Bool
+ecore_file_download_protocol_available(const char *protocol)
+{
+#ifdef BUILD_ECORE_CON
+ if (!strncmp(protocol, "file://", 7)) return EINA_TRUE;
+# ifdef HAVE_CURL
+ else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE;
+ else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE;
+# endif
+#else
+ (void)protocol;
+#endif /* BUILD_ECORE_CON */
+
+ return EINA_FALSE;
+}
+
+#ifdef BUILD_ECORE_CON
+
+# ifdef HAVE_CURL
+static int
+_ecore_file_download_url_compare_job(const void *data1, const void *data2)
+{
+ const Ecore_File_Download_Job *job = data1;
+ const Ecore_Con_Url *url = data2;
+
+ if (job->url_con == url) return 0;
+ return -1;
+}
+
+static Eina_Bool
+_ecore_file_download_url_complete_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Con_Event_Url_Complete *ev = event;
+ Ecore_File_Download_Job *job;
+
+ job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
+ if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
+
+ fclose(job->file);
+ if (job->completion_cb)
+ job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, ev->status);
+
+ _job_list = eina_list_remove(_job_list, job);
+ free(job->dst);
+ ecore_con_url_free(job->url_con);
+ free(job);
+
+ return ECORE_CALLBACK_DONE;
+}
+
+static Eina_Bool
+_ecore_file_download_url_progress_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+/* this reports the downloads progress. if we return 0, then download
+ * continues, if we return anything else, then the download stops */
+ Ecore_Con_Event_Url_Progress *ev = event;
+ Ecore_File_Download_Job *job;
+
+ job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
+ if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
+
+ if (job->progress_cb)
+ if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst,
+ (long int) ev->down.total, (long int) ev->down.now,
+ (long int) ev->up.total, (long int) ev->up.now) != 0)
+ {
+ _job_list = eina_list_remove(_job_list, job);
+ fclose(job->file);
+ free(job->dst);
+ free(job);
+
+ return ECORE_CALLBACK_PASS_ON;
+ }
+
+ return ECORE_CALLBACK_DONE;
+}
+
+Ecore_File_Download_Job *
+_ecore_file_download_curl(const char *url, const char *dst,
+ Ecore_File_Download_Completion_Cb completion_cb,
+ Ecore_File_Download_Progress_Cb progress_cb,
+ void *data,
+ Eina_Hash *headers)
+{
+ Ecore_File_Download_Job *job;
+
+ job = calloc(1, sizeof(Ecore_File_Download_Job));
+ if (!job) return NULL;
+
+ ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB);
+
+ job->file = fopen(dst, "wb");
+ if (!job->file)
+ {
+ free(job);
+ return NULL;
+ }
+ job->url_con = ecore_con_url_new(url);
+ if (!job->url_con)
+ {
+ fclose(job->file);
+ free(job);
+ return NULL;
+ }
+
+ if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job);
+ ecore_con_url_fd_set(job->url_con, fileno(job->file));
+ ecore_con_url_data_set(job->url_con, data);
+
+ job->dst = strdup(dst);
+
+ job->completion_cb = completion_cb;
+ job->progress_cb = progress_cb;
+ _job_list = eina_list_append(_job_list, job);
+
+ if (!ecore_con_url_get(job->url_con))
+ {
+ ecore_con_url_free(job->url_con);
+ _job_list = eina_list_remove(_job_list, job);
+ fclose(job->file);
+ ecore_file_remove(job->dst);
+ free(job->dst);
+ free(job);
+ return NULL;
+ }
+
+ return job;
+}
+# endif
+#endif
+
+/**
+ * @brief Abort the given download job and call the completion_cb
+ * callbck with a status of 1 (error).
+ *
+ * @param job The download job to abort.
+ *
+ * This function aborts a download operation started by
+ * ecore_file_download(). @p job is the #Ecore_File_Download_Job
+ * structure filled by ecore_file_download(). If it is @c NULL, this
+ * function does nothing. To abort all the currently downloading
+ * operations, call ecore_file_download_abort_all().
+ */
+EAPI void
+ecore_file_download_abort(Ecore_File_Download_Job *job)
+{
+ if (!job)
+ return;
+
+#ifdef BUILD_ECORE_CON
+ if (job->completion_cb)
+ job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, 1);
+# ifdef HAVE_CURL
+ ecore_con_url_free(job->url_con);
+# endif
+ _job_list = eina_list_remove(_job_list, job);
+ fclose(job->file);
+ free(job->dst);
+ free(job);
+#endif /* BUILD_ECORE_CON */
+}
+
+/**
+ * @brief Abort all downloads.
+ *
+ * This function aborts all the downloads that have been started by
+ * ecore_file_download(). It loops over the started downloads and call
+ * ecore_file_download_abort() for each of them. To abort only one
+ * specific download operation, call ecore_file_download_abort().
+ */
+EAPI void
+ecore_file_download_abort_all(void)
+{
+#ifdef BUILD_ECORE_CON
+ Ecore_File_Download_Job *job;
+
+ EINA_LIST_FREE(_job_list, job)
+ ecore_file_download_abort(job);
+#endif /* BUILD_ECORE_CON */
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_file/ecore_file_monitor.c b/src/lib/ecore_file/ecore_file_monitor.c
new file mode 100644
index 0000000000..8b07589a9e
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_monitor.c
@@ -0,0 +1,180 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecore_file_private.h"
+
+typedef enum {
+ ECORE_FILE_MONITOR_TYPE_NONE,
+#ifdef HAVE_INOTIFY
+ ECORE_FILE_MONITOR_TYPE_INOTIFY,
+#endif
+#ifdef HAVE_NOTIFY_WIN32
+ ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32,
+#endif
+#ifdef HAVE_POLL
+ ECORE_FILE_MONITOR_TYPE_POLL
+#endif
+} Ecore_File_Monitor_Type;
+
+static Ecore_File_Monitor_Type monitor_type = ECORE_FILE_MONITOR_TYPE_NONE;
+
+int
+ecore_file_monitor_init(void)
+{
+#ifdef HAVE_INOTIFY
+ monitor_type = ECORE_FILE_MONITOR_TYPE_INOTIFY;
+ if (ecore_file_monitor_inotify_init())
+ return 1;
+#endif
+#ifdef HAVE_NOTIFY_WIN32
+ monitor_type = ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32;
+ if (ecore_file_monitor_win32_init())
+ return 1;
+#endif
+#ifdef HAVE_POLL
+ monitor_type = ECORE_FILE_MONITOR_TYPE_POLL;
+ if (ecore_file_monitor_poll_init())
+ return 1;
+#endif
+ monitor_type = ECORE_FILE_MONITOR_TYPE_NONE;
+ return 0;
+}
+
+void
+ecore_file_monitor_shutdown(void)
+{
+ switch (monitor_type)
+ {
+ case ECORE_FILE_MONITOR_TYPE_NONE:
+ break;
+#ifdef HAVE_INOTIFY
+ case ECORE_FILE_MONITOR_TYPE_INOTIFY:
+ ecore_file_monitor_inotify_shutdown();
+ break;
+#endif
+#ifdef HAVE_NOTIFY_WIN32
+ case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
+ ecore_file_monitor_win32_shutdown();
+ break;
+#endif
+#ifdef HAVE_POLL
+ case ECORE_FILE_MONITOR_TYPE_POLL:
+ ecore_file_monitor_poll_shutdown();
+ break;
+#endif
+ }
+}
+
+/**
+ * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
+ *
+ * @{
+ */
+
+/**
+ * @brief Monitor the given path using inotify, Windows notification, or polling.
+ *
+ * @param path The path to monitor.
+ * @param func The function to call on changes.
+ * @param data The data passed to func.
+ * @return An Ecore_File_Monitor pointer or NULL on failure.
+ *
+ * This function monitors @p path. If @p path is @c NULL, or is an
+ * empty string, or none of the notify methods (Inotify, Windows
+ * notification or polling) is available, or if @p path is not a file,
+ * the function returns @c NULL. Otherwise, it returns a newly
+ * allocated Ecore_File_Monitor object and the monitoring begins. When
+ * one of the Ecore_File_Event event is notified, @p func is called
+ * and @p data is passed to @p func. Call ecore_file_monitor_del() to
+ * stop the monitoring.
+ */
+EAPI Ecore_File_Monitor *
+ecore_file_monitor_add(const char *path,
+ Ecore_File_Monitor_Cb func,
+ void *data)
+{
+ if (!path || !*path)
+ return NULL;
+
+ switch (monitor_type)
+ {
+ case ECORE_FILE_MONITOR_TYPE_NONE:
+ return NULL;
+#ifdef HAVE_INOTIFY
+ case ECORE_FILE_MONITOR_TYPE_INOTIFY:
+ return ecore_file_monitor_inotify_add(path, func, data);
+#endif
+#ifdef HAVE_NOTIFY_WIN32
+ case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
+ return ecore_file_monitor_win32_add(path, func, data);
+#endif
+#ifdef HAVE_POLL
+ case ECORE_FILE_MONITOR_TYPE_POLL:
+ return ecore_file_monitor_poll_add(path, func, data);
+#endif
+ }
+ return NULL;
+}
+
+/**
+ * @brief Stop the monitoring of the given path.
+ *
+ * @param em The Ecore_File_Monitor to stop.
+ *
+ * This function stops the the monitoring of the path that has been
+ * monitored by ecore_file_monitor_add(). @p em must be the value
+ * returned by ecore_file_monitor_add(). If @p em is @c NULL, or none
+ * of the notify methods (Inotify, Windows notification or polling) is
+ * availablethis function does nothing.
+ */
+EAPI void
+ecore_file_monitor_del(Ecore_File_Monitor *em)
+{
+ if (!em)
+ return;
+
+ switch (monitor_type)
+ {
+ case ECORE_FILE_MONITOR_TYPE_NONE:
+ break;
+#ifdef HAVE_INOTIFY
+ case ECORE_FILE_MONITOR_TYPE_INOTIFY:
+ ecore_file_monitor_inotify_del(em);
+ break;
+#endif
+#ifdef HAVE_NOTIFY_WIN32
+ case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
+ ecore_file_monitor_win32_del(em);
+ break;
+#endif
+#ifdef HAVE_POLL
+ case ECORE_FILE_MONITOR_TYPE_POLL:
+ ecore_file_monitor_poll_del(em);
+ break;
+#endif
+ }
+}
+
+/**
+ * @brief Get the monitored path.
+ *
+ * @param em The Ecore_File_Monitor to query.
+ * @return The path that is monitored by @p em.
+ *
+ * This function returns the monitored path that has been
+ * monitored by ecore_file_monitor_add(). @p em must be the value
+ * returned by ecore_file_monitor_add(). If @p em is @c NULL, the
+ * function returns @c NULL.
+ */
+EAPI const char *
+ecore_file_monitor_path_get(Ecore_File_Monitor *em)
+{
+ if (!em)
+ return NULL;
+ return em->path;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_file/ecore_file_monitor_inotify.c b/src/lib/ecore_file/ecore_file_monitor_inotify.c
new file mode 100644
index 0000000000..1b682fc4a0
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_monitor_inotify.c
@@ -0,0 +1,331 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "ecore_file_private.h"
+
+/*
+ * TODO:
+ *
+ * - Listen to these events:
+ * IN_ACCESS, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, IN_OPEN
+ * - Read all events first, then call the callbacks. This will prevent several
+ * callbacks with the typic save cycle (delete file, new file)
+ * - Listen to IN_IGNORED, emitted when the watch is removed
+ */
+
+#ifdef HAVE_INOTIFY
+
+#include <sys/inotify.h>
+
+
+typedef struct _Ecore_File_Monitor_Inotify Ecore_File_Monitor_Inotify;
+
+#define ECORE_FILE_MONITOR_INOTIFY(x) ((Ecore_File_Monitor_Inotify *)(x))
+
+struct _Ecore_File_Monitor_Inotify
+{
+ Ecore_File_Monitor monitor;
+ int wd;
+};
+
+static Ecore_Fd_Handler *_fdh = NULL;
+static Ecore_File_Monitor *_monitors = NULL;
+static pid_t _inotify_fd_pid = -1;
+
+static Eina_Bool _ecore_file_monitor_inotify_handler(void *data, Ecore_Fd_Handler *fdh);
+static Ecore_File_Monitor *_ecore_file_monitor_inotify_monitor_find(int wd);
+static void _ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask);
+static int _ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path);
+#if 0
+static void _ecore_file_monitor_inotify_print(char *file, int mask);
+#endif
+
+int
+ecore_file_monitor_inotify_init(void)
+{
+ int fd;
+
+ fd = inotify_init();
+ if (fd < 0)
+ return 0;
+
+ _fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _ecore_file_monitor_inotify_handler,
+ NULL, NULL, NULL);
+ if (!_fdh)
+ {
+ close(fd);
+ return 0;
+ }
+
+ _inotify_fd_pid = getpid();
+ return 1;
+}
+
+int
+ecore_file_monitor_inotify_shutdown(void)
+{
+ int fd;
+
+ while(_monitors)
+ ecore_file_monitor_inotify_del(_monitors);
+
+ if (_fdh)
+ {
+ fd = ecore_main_fd_handler_fd_get(_fdh);
+ ecore_main_fd_handler_del(_fdh);
+ close(fd);
+ }
+ _inotify_fd_pid = -1;
+ return 1;
+}
+
+Ecore_File_Monitor *
+ecore_file_monitor_inotify_add(const char *path,
+ void (*func) (void *data, Ecore_File_Monitor *em,
+ Ecore_File_Event event,
+ const char *path),
+ void *data)
+{
+ Ecore_File_Monitor *em;
+ int len;
+
+ if (_inotify_fd_pid == -1) return NULL;
+
+ if (_inotify_fd_pid != getpid())
+ {
+ ecore_file_monitor_inotify_shutdown();
+ ecore_file_monitor_inotify_init();
+ }
+
+ em = calloc(1, sizeof(Ecore_File_Monitor_Inotify));
+ if (!em) return NULL;
+
+ em->func = func;
+ em->data = data;
+
+ em->path = strdup(path);
+ len = strlen(em->path);
+ if (em->path[len - 1] == '/' && strcmp(em->path, "/"))
+ em->path[len - 1] = 0;
+
+ _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
+
+ if (!_ecore_file_monitor_inotify_monitor(em, em->path))
+ return NULL;
+
+ return em;
+}
+
+void
+ecore_file_monitor_inotify_del(Ecore_File_Monitor *em)
+{
+ int fd;
+
+ if (_monitors)
+ _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
+
+ fd = ecore_main_fd_handler_fd_get(_fdh);
+ if (ECORE_FILE_MONITOR_INOTIFY(em)->wd)
+ inotify_rm_watch(fd, ECORE_FILE_MONITOR_INOTIFY(em)->wd);
+ free(em->path);
+ free(em);
+}
+
+static Eina_Bool
+_ecore_file_monitor_inotify_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh)
+{
+ Ecore_File_Monitor *em;
+ char buffer[16384];
+ struct inotify_event *event;
+ int i = 0;
+ int event_size;
+ ssize_t size;
+
+ size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer));
+ while (i < size)
+ {
+ event = (struct inotify_event *)&buffer[i];
+ event_size = sizeof(struct inotify_event) + event->len;
+ i += event_size;
+
+ em = _ecore_file_monitor_inotify_monitor_find(event->wd);
+ if (!em) continue;
+
+ _ecore_file_monitor_inotify_events(em, (event->len ? event->name : NULL), event->mask);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Ecore_File_Monitor *
+_ecore_file_monitor_inotify_monitor_find(int wd)
+{
+ Ecore_File_Monitor *l;
+
+ EINA_INLIST_FOREACH(_monitors, l)
+ {
+ if (ECORE_FILE_MONITOR_INOTIFY(l)->wd == wd)
+ return l;
+ }
+ return NULL;
+}
+
+static void
+_ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask)
+{
+ char buf[PATH_MAX];
+ int isdir;
+
+ if ((file) && (file[0]))
+ snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
+ else
+ strcpy(buf, em->path);
+ isdir = mask & IN_ISDIR;
+
+#if 0
+ _ecore_file_monitor_inotify_print(buf, mask);
+#endif
+
+ if (mask & IN_ATTRIB)
+ {
+ em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
+ }
+ if (mask & IN_CLOSE_WRITE)
+ {
+ if (!isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_CLOSED, buf);
+ }
+ if (mask & IN_MODIFY)
+ {
+ if (!isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
+ }
+ if (mask & IN_MOVED_FROM)
+ {
+ if (isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf);
+ else
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf);
+ }
+ if (mask & IN_MOVED_TO)
+ {
+ if (isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf);
+ else
+ em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf);
+ }
+ if (mask & IN_DELETE)
+ {
+ if (isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf);
+ else
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf);
+ }
+ if (mask & IN_CREATE)
+ {
+ if (isdir)
+ em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf);
+ else
+ em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf);
+ }
+ if (mask & IN_DELETE_SELF)
+ {
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ }
+ if (mask & IN_MOVE_SELF)
+ {
+ /* We just call delete. The dir is gone... */
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ }
+ if (mask & IN_UNMOUNT)
+ {
+ /* We just call delete. The dir is gone... */
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ }
+ if (mask & IN_IGNORED)
+ {
+ /* The watch is removed. If the file name still exists monitor the new one,
+ * else delete it */
+ if (ecore_file_exists(em->path))
+ {
+ if (_ecore_file_monitor_inotify_monitor(em, em->path))
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ }
+ else
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ }
+}
+
+static int
+_ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path)
+{
+ int mask =
+ IN_ATTRIB |
+ IN_CLOSE_WRITE |
+ IN_MOVED_FROM |
+ IN_MOVED_TO |
+ IN_DELETE |
+ IN_CREATE |
+ IN_MODIFY |
+ IN_DELETE_SELF |
+ IN_MOVE_SELF |
+ IN_UNMOUNT;
+
+ ECORE_FILE_MONITOR_INOTIFY(em)->wd =
+ inotify_add_watch(ecore_main_fd_handler_fd_get(_fdh), path, mask);
+ if (ECORE_FILE_MONITOR_INOTIFY(em)->wd < 0)
+ {
+ INF("inotify_add_watch failed, file was deleted");
+ ecore_file_monitor_inotify_del(em);
+ return 0;
+ }
+ return 1;
+}
+
+#if 0
+static void
+_ecore_file_monitor_inotify_print(char *file, int mask)
+{
+ const char *type;
+
+ if (mask & IN_ISDIR)
+ type = "dir";
+ else
+ type = "file";
+
+ if (mask & IN_ACCESS)
+ INF("Inotify accessed %s: %s", type, file);
+ if (mask & IN_MODIFY)
+ INF("Inotify modified %s: %s", type, file);
+ if (mask & IN_ATTRIB)
+ INF("Inotify attributes %s: %s", type, file);
+ if (mask & IN_CLOSE_WRITE)
+ INF("Inotify close write %s: %s", type, file);
+ if (mask & IN_CLOSE_NOWRITE)
+ INF("Inotify close write %s: %s", type, file);
+ if (mask & IN_OPEN)
+ INF("Inotify open %s: %s", type, file);
+ if (mask & IN_MOVED_FROM)
+ INF("Inotify moved from %s: %s", type, file);
+ if (mask & IN_MOVED_TO)
+ INF("Inotify moved to %s: %s", type, file);
+ if (mask & IN_DELETE)
+ INF("Inotify delete %s: %s", type, file);
+ if (mask & IN_CREATE)
+ INF("Inotify create %s: %s", type, file);
+ if (mask & IN_DELETE_SELF)
+ INF("Inotify delete self %s: %s", type, file);
+ if (mask & IN_MOVE_SELF)
+ INF("Inotify move self %s: %s", type, file);
+ if (mask & IN_UNMOUNT)
+ INF("Inotify unmount %s: %s", type, file);
+}
+#endif
+#endif /* HAVE_INOTIFY */
diff --git a/src/lib/ecore_file/ecore_file_monitor_poll.c b/src/lib/ecore_file/ecore_file_monitor_poll.c
new file mode 100644
index 0000000000..68889a74e8
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_monitor_poll.c
@@ -0,0 +1,340 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ecore_file_private.h"
+
+#ifdef HAVE_POLL
+
+/*
+ * TODO:
+ * - Implement recursive as an option!
+ * - Keep whole path or just name of file? (Memory or CPU...)
+ * - Remove requests without files?
+ * - Change poll time
+ */
+
+typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll;
+
+#define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x))
+
+struct _Ecore_File_Monitor_Poll
+{
+ Ecore_File_Monitor monitor;
+ int mtime;
+ unsigned char deleted;
+};
+
+#define ECORE_FILE_INTERVAL_MIN 1.0
+#define ECORE_FILE_INTERVAL_STEP 0.5
+#define ECORE_FILE_INTERVAL_MAX 5.0
+
+static double _interval = ECORE_FILE_INTERVAL_MIN;
+static Ecore_Timer *_timer = NULL;
+static Ecore_File_Monitor *_monitors = NULL;
+static int _lock = 0;
+
+static Eina_Bool _ecore_file_monitor_poll_handler(void *data);
+static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em);
+static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name);
+
+int
+ecore_file_monitor_poll_init(void)
+{
+ return 1;
+}
+
+int
+ecore_file_monitor_poll_shutdown(void)
+{
+ while(_monitors)
+ ecore_file_monitor_poll_del(_monitors);
+
+ if (_timer)
+ {
+ ecore_timer_del(_timer);
+ _timer = NULL;
+ }
+ return 1;
+}
+
+Ecore_File_Monitor *
+ecore_file_monitor_poll_add(const char *path,
+ void (*func) (void *data, Ecore_File_Monitor *em,
+ Ecore_File_Event event,
+ const char *path),
+ void *data)
+{
+ Ecore_File_Monitor *em;
+ size_t len;
+
+ if (!path) return NULL;
+ if (!func) return NULL;
+
+ em = calloc(1, sizeof(Ecore_File_Monitor_Poll));
+ if (!em) return NULL;
+
+ if (!_timer)
+ _timer = ecore_timer_add(_interval, _ecore_file_monitor_poll_handler, NULL);
+ else
+ ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN);
+
+ em->path = strdup(path);
+ len = strlen(em->path);
+ if (em->path[len - 1] == '/' && strcmp(em->path, "/"))
+ em->path[len - 1] = 0;
+
+ em->func = func;
+ em->data = data;
+
+ ECORE_FILE_MONITOR_POLL(em)->mtime = ecore_file_mod_time(em->path);
+ _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
+
+ if (ecore_file_exists(em->path))
+ {
+ if (ecore_file_is_dir(em->path))
+ {
+ /* Check for subdirs */
+ Eina_List *files;
+ char *file;
+
+ files = ecore_file_ls(em->path);
+ EINA_LIST_FREE(files, file)
+ {
+ Ecore_File *f;
+ char buf[PATH_MAX];
+
+ f = calloc(1, sizeof(Ecore_File));
+ if (!f)
+ {
+ free(file);
+ continue;
+ }
+
+ snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
+ f->name = file;
+ f->mtime = ecore_file_mod_time(buf);
+ f->is_dir = ecore_file_is_dir(buf);
+ em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
+ }
+ }
+ }
+ else
+ {
+ ecore_file_monitor_poll_del(em);
+ return NULL;
+ }
+
+ return em;
+}
+
+void
+ecore_file_monitor_poll_del(Ecore_File_Monitor *em)
+{
+ Ecore_File *l;
+
+ if (_lock)
+ {
+ ECORE_FILE_MONITOR_POLL(em)->deleted = 1;
+ return;
+ }
+
+ /* Remove files */
+ /*It's possible there weren't any files to monitor, so check if the list is init*/
+ if (em->files)
+ {
+ for (l = em->files; l;)
+ {
+ Ecore_File *file = l;
+
+ l = (Ecore_File *) EINA_INLIST_GET(l)->next;
+ free(file->name);
+ free(file);
+ }
+ }
+
+ if (_monitors)
+ _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
+
+ free(em->path);
+ free(em);
+
+ if (_timer)
+ {
+ if (!_monitors)
+ {
+ ecore_timer_del(_timer);
+ _timer = NULL;
+ }
+ else
+ ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN);
+ }
+}
+
+static Eina_Bool
+_ecore_file_monitor_poll_handler(void *data EINA_UNUSED)
+{
+ Ecore_File_Monitor *l;
+
+ _interval += ECORE_FILE_INTERVAL_STEP;
+
+ _lock = 1;
+ EINA_INLIST_FOREACH(_monitors, l)
+ _ecore_file_monitor_poll_check(l);
+ _lock = 0;
+
+ if (_interval > ECORE_FILE_INTERVAL_MAX)
+ _interval = ECORE_FILE_INTERVAL_MAX;
+ ecore_timer_interval_set(_timer, _interval);
+
+ for (l = _monitors; l;)
+ {
+ Ecore_File_Monitor *em = l;
+
+ l = ECORE_FILE_MONITOR(EINA_INLIST_GET(l)->next);
+ if (ECORE_FILE_MONITOR_POLL(em)->deleted)
+ ecore_file_monitor_del(em);
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_file_monitor_poll_check(Ecore_File_Monitor *em)
+{
+ int mtime;
+
+ mtime = ecore_file_mod_time(em->path);
+ if (mtime < ECORE_FILE_MONITOR_POLL(em)->mtime)
+ {
+ Ecore_File *l;
+ Ecore_File_Event event;
+
+ /* Notify all files deleted */
+ for (l = em->files; l;)
+ {
+ Ecore_File *f = l;
+ char buf[PATH_MAX];
+
+ l = (Ecore_File *) EINA_INLIST_GET(l)->next;
+
+ snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
+ if (f->is_dir)
+ event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_DELETED_FILE;
+ em->func(em->data, em, event, buf);
+ free(f->name);
+ free(f);
+ }
+ em->files = NULL;
+ em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
+ _interval = ECORE_FILE_INTERVAL_MIN;
+ }
+ else
+ {
+ Ecore_File *l;
+
+ /* Check for changed files */
+ for (l = em->files; l;)
+ {
+ Ecore_File *f = l;
+ char buf[PATH_MAX];
+ int mt;
+ Ecore_File_Event event;
+
+ l = (Ecore_File *) EINA_INLIST_GET(l)->next;
+
+ snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
+ mt = ecore_file_mod_time(buf);
+ if (mt < f->mtime)
+ {
+ if (f->is_dir)
+ event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_DELETED_FILE;
+
+ em->func(em->data, em, event, buf);
+ em->files = (Ecore_File *) eina_inlist_remove(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
+ free(f->name);
+ free(f);
+ _interval = ECORE_FILE_INTERVAL_MIN;
+ }
+ else if ((mt > f->mtime) && !(f->is_dir))
+ {
+ em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
+ _interval = ECORE_FILE_INTERVAL_MIN;
+ f->mtime = mt;
+ }
+ else
+ f->mtime = mt;
+ }
+
+ /* Check for new files */
+ if (ECORE_FILE_MONITOR_POLL(em)->mtime < mtime)
+ {
+ Eina_List *files;
+ Eina_List *fl;
+ char *file;
+
+ /* Files have been added or removed */
+ files = ecore_file_ls(em->path);
+ if (files)
+ {
+ /* Are we a directory? We should check first, rather than rely on null here*/
+ EINA_LIST_FOREACH(files, fl, file)
+ {
+ Ecore_File *f;
+ char buf[PATH_MAX];
+ Ecore_File_Event event;
+
+ if (_ecore_file_monitor_poll_checking(em, file))
+ continue;
+
+ snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
+ f = calloc(1, sizeof(Ecore_File));
+ if (!f)
+ continue;
+
+ f->name = strdup(file);
+ f->mtime = ecore_file_mod_time(buf);
+ f->is_dir = ecore_file_is_dir(buf);
+ if (f->is_dir)
+ event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_CREATED_FILE;
+ em->func(em->data, em, event, buf);
+ em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
+ }
+ while (files)
+ {
+ file = eina_list_data_get(files);
+ free(file);
+ files = eina_list_remove_list(files, files);
+ }
+ }
+
+ if (!ecore_file_is_dir(em->path))
+ em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, em->path);
+ _interval = ECORE_FILE_INTERVAL_MIN;
+ }
+ }
+ ECORE_FILE_MONITOR_POLL(em)->mtime = mtime;
+}
+
+static int
+_ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name)
+{
+ Ecore_File *l;
+
+ EINA_INLIST_FOREACH(em->files, l)
+ {
+ if (!strcmp(l->name, name))
+ return 1;
+ }
+ return 0;
+}
+#endif
diff --git a/src/lib/ecore_file/ecore_file_monitor_win32.c b/src/lib/ecore_file/ecore_file_monitor_win32.c
new file mode 100644
index 0000000000..7f3af0907b
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_monitor_win32.c
@@ -0,0 +1,310 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_NOTIFY_WIN32
+
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# include <process.h>
+
+# include "ecore_file_private.h"
+
+
+typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32;
+typedef struct _Ecore_File_Monitor_Win32_Data Ecore_File_Monitor_Win32_Data;
+
+/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */
+# define ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE 4096
+# define ECORE_FILE_MONITOR_WIN32(x) ((Ecore_File_Monitor_Win32 *)(x))
+
+struct _Ecore_File_Monitor_Win32_Data
+{
+ char buffer[ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE];
+ OVERLAPPED overlapped;
+ HANDLE handle;
+ HANDLE event;
+ Ecore_File_Monitor *monitor;
+ Ecore_Win32_Handler *h;
+ DWORD buf_length;
+ int is_dir;
+};
+
+struct _Ecore_File_Monitor_Win32
+{
+ Ecore_File_Monitor monitor;
+ Ecore_File_Monitor_Win32_Data *file;
+ Ecore_File_Monitor_Win32_Data *dir;
+};
+
+static Ecore_File_Monitor *_monitors = NULL;
+
+static Eina_Bool _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh);
+
+
+static Ecore_File_Monitor_Win32_Data *
+_ecore_file_monitor_win32_data_new(Ecore_File_Monitor *monitor, int type)
+{
+ Ecore_File_Monitor_Win32_Data *md;
+ DWORD filter;
+
+ md = (Ecore_File_Monitor_Win32_Data *)calloc(1, sizeof(Ecore_File_Monitor_Win32_Data));
+ if (!md) return NULL;
+
+ md->handle = CreateFile(monitor->path,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (md->handle == INVALID_HANDLE_VALUE)
+ goto free_md;
+
+ md->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!md->event)
+ goto close_handle;
+
+ ZeroMemory (&md->overlapped, sizeof(md->overlapped));
+ md->overlapped.hEvent = md->event;
+
+ filter = (type == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
+ filter |=
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY;
+
+ if (!ReadDirectoryChangesW(md->handle,
+ md->buffer,
+ ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
+ FALSE,
+ filter,
+ &md->buf_length,
+ &md->overlapped,
+ NULL))
+ goto close_event;
+
+ md->h = ecore_main_win32_handler_add(md->event,
+ _ecore_file_monitor_win32_cb,
+ md);
+ if (!md->h)
+ goto close_event;
+
+ md->monitor = monitor;
+ md->is_dir = type;
+
+ return md;
+
+ close_event:
+ CloseHandle(md->event);
+ close_handle:
+ CloseHandle(md->handle);
+ free_md:
+ free(md);
+
+ return NULL;
+}
+
+static void
+_ecore_file_monitor_win32_data_free(Ecore_File_Monitor_Win32_Data *md)
+{
+ if (!md) return;
+
+ CloseHandle(md->event);
+ CloseHandle (md->handle);
+ free (md);
+}
+
+static Eina_Bool
+_ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh)
+{
+ char filename[PATH_MAX];
+ PFILE_NOTIFY_INFORMATION fni;
+ Ecore_File_Monitor_Win32_Data *md;
+ wchar_t *wname;
+ char *name;
+ DWORD filter;
+ DWORD offset;
+ DWORD buf_length;
+ Ecore_File_Event event = ECORE_FILE_EVENT_NONE;
+
+ md = (Ecore_File_Monitor_Win32_Data *)data;
+
+ if (!GetOverlappedResult (md->handle, &md->overlapped, &buf_length, TRUE))
+ return 1;
+
+ fni = (PFILE_NOTIFY_INFORMATION)md->buffer;
+ do {
+ if (!fni)
+ break;
+ offset = fni->NextEntryOffset;
+
+ wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1));
+ if (!wname)
+ return 0;
+
+ memcpy(wname, fni->FileName, fni->FileNameLength);
+ wname[fni->FileNameLength]='\0';
+ name = evil_wchar_to_char(wname);
+ free(wname);
+ if (!name)
+ return 0;
+
+ _snprintf(filename, PATH_MAX, "%s\\%s", md->monitor->path, name);
+ free(name);
+
+ switch (fni->Action)
+ {
+ case FILE_ACTION_ADDED:
+ if (md->is_dir)
+ event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_CREATED_FILE;
+ break;
+ case FILE_ACTION_REMOVED:
+ if (md->is_dir)
+ event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_DELETED_FILE;
+ break;
+ case FILE_ACTION_MODIFIED:
+ if (!md->is_dir)
+ event = ECORE_FILE_EVENT_MODIFIED;
+ break;
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ if (md->is_dir)
+ event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_DELETED_FILE;
+ break;
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ if (md->is_dir)
+ event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
+ else
+ event = ECORE_FILE_EVENT_CREATED_FILE;
+ break;
+ default:
+ fprintf(stderr, "unknown event\n");
+ event = ECORE_FILE_EVENT_NONE;
+ break;
+ }
+ if (event != ECORE_FILE_EVENT_NONE)
+ md->monitor->func(md->monitor->data, md->monitor, event, filename);
+
+ fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset);
+ } while (offset);
+
+ filter = (md->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
+ filter |=
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY;
+
+ ReadDirectoryChangesW(md->handle,
+ md->buffer,
+ ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
+ FALSE,
+ filter,
+ &md->buf_length,
+ &md->overlapped,
+ NULL);
+ return 1;
+}
+
+int
+ecore_file_monitor_win32_init(void)
+{
+ return 1;
+}
+
+int
+ecore_file_monitor_win32_shutdown(void)
+{
+ return 1;
+}
+
+Ecore_File_Monitor *
+ecore_file_monitor_win32_add(const char *path,
+ void (*func) (void *data, Ecore_File_Monitor *em,
+ Ecore_File_Event event,
+ const char *path),
+ void *data)
+{
+ Ecore_File_Monitor_Win32 *m;
+ Ecore_File_Monitor *em;
+ size_t len;
+
+ if (!path || (*path == '\0')) return NULL;
+ if (!ecore_file_exists(path) || !ecore_file_is_dir(path))
+ return NULL;
+ if (!func) return NULL;
+
+ em = (Ecore_File_Monitor *)calloc(1, sizeof(Ecore_File_Monitor_Win32));
+ if (!em) return NULL;
+
+ em->func = func;
+ em->data = data;
+
+ em->path = strdup(path);
+ if (!em->path)
+ {
+ free(em);
+ return NULL;
+ }
+ len = strlen(em->path);
+ if (em->path[len - 1] == '/' || em->path[len - 1] == '\\')
+ em->path[len - 1] = '\0';
+
+ m = ECORE_FILE_MONITOR_WIN32(em);
+
+ m->file = _ecore_file_monitor_win32_data_new(em, 0);
+ if (!m->file)
+ {
+ free(em->path);
+ free(em);
+ return NULL;
+ }
+
+ m->dir = _ecore_file_monitor_win32_data_new(em, 1);
+ if (!m->dir)
+ {
+ _ecore_file_monitor_win32_data_free(m->file);
+ free(em->path);
+ free(em);
+ return NULL;
+ }
+
+ _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
+
+ return em;
+}
+
+void
+ecore_file_monitor_win32_del(Ecore_File_Monitor *em)
+{
+ Ecore_File_Monitor_Win32 *m;
+
+ if (!em)
+ return;
+
+ m = ECORE_FILE_MONITOR_WIN32(em);
+ _ecore_file_monitor_win32_data_free(m->dir);
+ _ecore_file_monitor_win32_data_free(m->file);
+ free(em->path);
+ free(em);
+}
+
+#endif
diff --git a/src/lib/ecore_file/ecore_file_path.c b/src/lib/ecore_file/ecore_file_path.c
new file mode 100644
index 0000000000..c1c54b7c0f
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_path.c
@@ -0,0 +1,192 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ecore_file_private.h"
+
+static Eina_List *__ecore_file_path_bin = NULL;
+
+static Eina_List *_ecore_file_path_from_env(const char *env);
+
+void
+ecore_file_path_init(void)
+{
+ __ecore_file_path_bin = _ecore_file_path_from_env("PATH");
+}
+
+void
+ecore_file_path_shutdown(void)
+{
+ char *dir;
+
+ EINA_LIST_FREE(__ecore_file_path_bin, dir)
+ eina_stringshare_del(dir);
+}
+
+Eina_List *
+_ecore_file_path_from_env(const char *env)
+{
+ Eina_List *path = NULL;
+ char *env_tmp, *env_path, *p, *last;
+
+ env_tmp = getenv(env);
+ if (!env_tmp)
+ return path;
+
+ env_path = alloca(sizeof(char) * strlen(env_tmp) + 1);
+ memset(env_path, 0, strlen(env_tmp));
+ strcpy(env_path, env_tmp);
+ last = env_path;
+ for (p = env_path; *p; p++)
+ {
+ if (*p == ':')
+ *p = '\0';
+
+ if (!*p)
+ {
+ if (!ecore_file_path_dir_exists(last))
+ path = eina_list_append(path, eina_stringshare_add(last));
+ last = p + 1;
+ }
+ }
+ if (p > last)
+ path = eina_list_append(path, eina_stringshare_add(last));
+
+ return path;
+}
+
+/**
+ * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions
+ *
+ * @{
+ */
+
+/**
+ * @brief Check if the given directory is in PATH.
+ *
+ * @param in_dir The name of the directory to search in PATH.
+ * @return @c EINA_TRUE if the directory exist in PATH, @c EINA_FALSE otherwise.
+ *
+ * This function checks if @p in_dir is in the environment variable
+ * PATH. If @p in_dir is @c NULL, or if PATH is empty, or @p in_dir is
+ * not in PATH, the function returns @c EINA_FALSE, otherwise it returns
+ * @c EINA_TRUE.
+ */
+EAPI Eina_Bool
+ecore_file_path_dir_exists(const char *in_dir)
+{
+ Eina_List *l;
+ char *dir;
+
+ if (!in_dir)
+ return EINA_FALSE;
+
+ if (!__ecore_file_path_bin) return EINA_FALSE;
+ EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir)
+ {
+ if (strcmp(dir, in_dir))
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given application is installed.
+ *
+ * @param exe The name of the application
+ * @return @c EINA_TRUE if the @p exe is in PATH and is executable,
+ * @c EINA_FALSE otherwise.
+ *
+ * This function checks if @p exe exists in PATH and is executable. If
+ * @p exe is @c NULL or is not executable, the function returns
+ * @c EINA_FALSE, otherwise it returns @c EINA_TRUE.
+ */
+EAPI Eina_Bool
+ecore_file_app_installed(const char *exe)
+{
+ Eina_List *l;
+ char *dir;
+ char buf[PATH_MAX];
+
+ if (!exe) return EINA_FALSE;
+ if (ecore_file_can_exec(exe)) return EINA_TRUE;
+
+ EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir)
+ {
+ snprintf(buf, sizeof(buf), "%s/%s", dir, exe);
+ if (ecore_file_can_exec(buf))
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Get a list of all the applications installed on the system.
+ *
+ * @return An Eina_List containing all the executable files in the
+ * system.
+ *
+ * This function returns a list of allocated strings of all the
+ * executable files. If no files are found, the function returns
+ * @c NULL. When not needed anymore, the element of the list must be
+ * freed.
+ */
+EAPI Eina_List *
+ecore_file_app_list(void)
+{
+ Eina_List *list = NULL;
+ Eina_List *files;
+ Eina_List *l;
+ char buf[PATH_MAX], *dir, *exe;
+
+ EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir)
+ {
+ files = ecore_file_ls(dir);
+ EINA_LIST_FREE(files, exe)
+ {
+ snprintf(buf, sizeof(buf), "%s/%s", dir, exe);
+ if ((ecore_file_can_exec(buf)) &&
+ (!ecore_file_is_dir(buf)))
+ list = eina_list_append(list, strdup(buf));
+ free(exe);
+ }
+ }
+
+ return list;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_file/ecore_file_private.h b/src/lib/ecore_file/ecore_file_private.h
new file mode 100644
index 0000000000..45d2cbd65c
--- /dev/null
+++ b/src/lib/ecore_file/ecore_file_private.h
@@ -0,0 +1,129 @@
+#ifndef ECORE_FILE_PRIVATE_H_
+#define ECORE_FILE_PRIVATE_H_
+
+#ifdef __linux__
+# include <features.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef HAVE_ESCAPE
+# include <Escape.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#include "Ecore_File.h"
+
+extern int _ecore_file_log_dom;
+
+#ifdef ECORE_FILE_DEFAULT_LOG_COLOR
+#undef ECORE_FILE_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_FILE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_file_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_file_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_file_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_file_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_file_log_dom, __VA_ARGS__)
+
+/* ecore_file_monitor */
+int ecore_file_monitor_init(void);
+void ecore_file_monitor_shutdown(void);
+
+#define ECORE_FILE_MONITOR(x) ((Ecore_File_Monitor *)(x))
+
+typedef struct _Ecore_File Ecore_File;
+struct _Ecore_File
+{
+ EINA_INLIST;
+ char *name;
+ int mtime;
+ unsigned char is_dir;
+};
+
+struct _Ecore_File_Monitor
+{
+ EINA_INLIST;
+ void (*func) (void *data,
+ Ecore_File_Monitor *ecore_file_monitor,
+ Ecore_File_Event event,
+ const char *path);
+
+ char *path;
+ void *data;
+ Ecore_File *files;
+};
+
+#ifdef HAVE_INOTIFY
+int ecore_file_monitor_inotify_init(void);
+int ecore_file_monitor_inotify_shutdown(void);
+Ecore_File_Monitor *ecore_file_monitor_inotify_add(const char *path,
+ void (*func) (void *data,
+ Ecore_File_Monitor *ecore_file_monitor,
+ Ecore_File_Event event,
+ const char *path),
+ void *data);
+void ecore_file_monitor_inotify_del(Ecore_File_Monitor *ecore_file_monitor);
+#endif
+
+#ifdef HAVE_NOTIFY_WIN32
+int ecore_file_monitor_win32_init(void);
+int ecore_file_monitor_win32_shutdown(void);
+Ecore_File_Monitor *ecore_file_monitor_win32_add(const char *path,
+ void (*func) (void *data,
+ Ecore_File_Monitor *ecore_file_monitor,
+ Ecore_File_Event event,
+ const char *path),
+ void *data);
+void ecore_file_monitor_win32_del(Ecore_File_Monitor *ecore_file_monitor);
+#endif
+
+#ifdef HAVE_POLL
+int ecore_file_monitor_poll_init(void);
+int ecore_file_monitor_poll_shutdown(void);
+Ecore_File_Monitor *ecore_file_monitor_poll_add(const char *path,
+ void (*func) (void *data,
+ Ecore_File_Monitor *ecore_file_monitor,
+ Ecore_File_Event event,
+ const char *path),
+ void *data);
+void ecore_file_monitor_poll_del(Ecore_File_Monitor *ecore_file_monitor);
+
+#endif
+
+/* ecore_file_path */
+void ecore_file_path_init(void);
+void ecore_file_path_shutdown(void);
+
+/* ecore_file_download */
+int ecore_file_download_init(void);
+void ecore_file_download_shutdown(void);
+
+#endif
diff --git a/src/lib/ecore_imf/Ecore_IMF.h b/src/lib/ecore_imf/Ecore_IMF.h
new file mode 100644
index 0000000000..641ece74a3
--- /dev/null
+++ b/src/lib/ecore_imf/Ecore_IMF.h
@@ -0,0 +1,577 @@
+#ifndef _ECORE_IMF_H
+#define _ECORE_IMF_H
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_IMF_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_IMF_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup Ecore_IMF_Context_Group
+ *
+ * @{
+ */
+/* ecore_imf_context_input_panel_event_callback_add() flag */
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_STATE_EVENT, /**< called when the state of the input panel is changed. @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, /**< called when the language of the input panel is changed. @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_SHIFT_MODE_EVENT, /**< called when the shift key state of the input panel is changed @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, /**< called when the size of the input panel is changed. @since 1.7 */
+ ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, /**< called when the state of the candidate word panel is changed. @since 1.7 */
+ ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT /**< called when the size of the candidate word panel is changed. @since 1.7 */
+} Ecore_IMF_Input_Panel_Event;
+
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_STATE_SHOW, /**< Notification after the display of the input panel @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_STATE_HIDE, /**< Notification prior to the dismissal of the input panel @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW /**< Notification prior to the display of the input panel @since 1.7 */
+} Ecore_IMF_Input_Panel_State;
+
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_SHIFT_MODE_OFF, /**< @since 1.7 */
+ ECORE_IMF_INPUT_PANEL_SHIFT_MODE_ON /**< @since 1.7 */
+} Ecore_IMF_Input_Panel_Shift_Mode;
+
+typedef enum
+{
+ ECORE_IMF_CANDIDATE_PANEL_SHOW, /**< Notification after the display of the candidate word panel @since 1.7 */
+ ECORE_IMF_CANDIDATE_PANEL_HIDE /**< Notification prior to the dismissal of the candidate word panel @since 1.7 */
+} Ecore_IMF_Candidate_Panel_State;
+
+/* Events sent by the Input Method */
+typedef struct _Ecore_IMF_Event_Preedit_Start Ecore_IMF_Event_Preedit_Start;
+typedef struct _Ecore_IMF_Event_Preedit_End Ecore_IMF_Event_Preedit_End;
+typedef struct _Ecore_IMF_Event_Preedit_Changed Ecore_IMF_Event_Preedit_Changed;
+typedef struct _Ecore_IMF_Event_Commit Ecore_IMF_Event_Commit;
+typedef struct _Ecore_IMF_Event_Delete_Surrounding Ecore_IMF_Event_Delete_Surrounding;
+
+/* Events to filter */
+typedef struct _Ecore_IMF_Event_Mouse_Down Ecore_IMF_Event_Mouse_Down;
+typedef struct _Ecore_IMF_Event_Mouse_Up Ecore_IMF_Event_Mouse_Up;
+typedef struct _Ecore_IMF_Event_Mouse_In Ecore_IMF_Event_Mouse_In;
+typedef struct _Ecore_IMF_Event_Mouse_Out Ecore_IMF_Event_Mouse_Out;
+typedef struct _Ecore_IMF_Event_Mouse_Move Ecore_IMF_Event_Mouse_Move;
+typedef struct _Ecore_IMF_Event_Mouse_Wheel Ecore_IMF_Event_Mouse_Wheel;
+typedef struct _Ecore_IMF_Event_Key_Down Ecore_IMF_Event_Key_Down;
+typedef struct _Ecore_IMF_Event_Key_Up Ecore_IMF_Event_Key_Up;
+typedef union _Ecore_IMF_Event Ecore_IMF_Event;
+
+typedef struct _Ecore_IMF_Context Ecore_IMF_Context; /**< An Input Method Context */
+typedef struct _Ecore_IMF_Context_Class Ecore_IMF_Context_Class; /**< An Input Method Context class */
+typedef struct _Ecore_IMF_Context_Info Ecore_IMF_Context_Info; /**< An Input Method Context info */
+
+/* Preedit attribute info */
+typedef struct _Ecore_IMF_Preedit_Attr Ecore_IMF_Preedit_Attr;
+
+EAPI extern int ECORE_IMF_EVENT_PREEDIT_START;
+EAPI extern int ECORE_IMF_EVENT_PREEDIT_END;
+EAPI extern int ECORE_IMF_EVENT_PREEDIT_CHANGED;
+EAPI extern int ECORE_IMF_EVENT_COMMIT;
+EAPI extern int ECORE_IMF_EVENT_DELETE_SURROUNDING;
+
+typedef void (*Ecore_IMF_Event_Cb) (void *data, Ecore_IMF_Context *ctx, void *event_info);
+
+/**
+ * @typedef Ecore_IMF_Callback_Type
+ *
+ * Ecore IMF Event callback types.
+ *
+ * @see ecore_imf_context_event_callback_add()
+ */
+typedef enum
+{
+ ECORE_IMF_CALLBACK_PREEDIT_START, /**< "PREEDIT_START" is called when a new preediting sequence starts. @since 1.2 */
+ ECORE_IMF_CALLBACK_PREEDIT_END, /**< "PREEDIT_END" is called when a preediting sequence has been completed or canceled. @since 1.2 */
+ ECORE_IMF_CALLBACK_PREEDIT_CHANGED, /**< "PREEDIT_CHANGED" is called whenever the preedit sequence currently being entered has changed. @since 1.2 */
+ ECORE_IMF_CALLBACK_COMMIT, /**< "COMMIT" is called when a complete input sequence has been entered by the user @since 1.2 */
+ ECORE_IMF_CALLBACK_DELETE_SURROUNDING /**< "DELETE_SURROUNDING" is called when the input method needs to delete all or part of the context surrounding the cursor @since 1.2 */
+} Ecore_IMF_Callback_Type;
+
+/**
+ * @typedef Ecore_IMF_Event_Type
+ *
+ * Ecore IMF event types.
+ *
+ * @see ecore_imf_context_filter_event()
+ */
+typedef enum
+{
+ ECORE_IMF_EVENT_MOUSE_DOWN, /**< Mouse Down event */
+ ECORE_IMF_EVENT_MOUSE_UP, /**< Mouse Up event */
+ ECORE_IMF_EVENT_MOUSE_IN, /**< Mouse In event */
+ ECORE_IMF_EVENT_MOUSE_OUT, /**< Mouse Out event */
+ ECORE_IMF_EVENT_MOUSE_MOVE, /**< Mouse Move event */
+ ECORE_IMF_EVENT_MOUSE_WHEEL, /**< Mouse Wheel event */
+ ECORE_IMF_EVENT_KEY_DOWN, /**< Key Down event */
+ ECORE_IMF_EVENT_KEY_UP /**< Key Up event */
+} Ecore_IMF_Event_Type;
+/**
+ * @typedef Ecore_IMF_Keyboard_Modifiers
+ * Type for Ecore_IMF keyboard modifiers
+ */
+typedef enum
+{
+ ECORE_IMF_KEYBOARD_MODIFIER_NONE = 0, /**< No active modifiers */
+ ECORE_IMF_KEYBOARD_MODIFIER_CTRL = 1 << 0, /**< "Control" is pressed */
+ ECORE_IMF_KEYBOARD_MODIFIER_ALT = 1 << 1, /**< "Alt" is pressed */
+ ECORE_IMF_KEYBOARD_MODIFIER_SHIFT = 1 << 2, /**< "Shift" is pressed */
+ ECORE_IMF_KEYBOARD_MODIFIER_WIN = 1 << 3, /**< "Win" (between "Ctrl" and "Alt") is pressed */
+ ECORE_IMF_KEYBOARD_MODIFIER_ALTGR = 1 << 4 /**< "AltGr" is pressed @since 1.7 */
+} Ecore_IMF_Keyboard_Modifiers;
+
+/**
+ * @typedef Ecore_IMF_Keyboard_Locks
+ * Type for Ecore_IMF keyboard locks
+ */
+typedef enum
+{
+ ECORE_IMF_KEYBOARD_LOCK_NONE = 0, /**< No locks are active */
+ ECORE_IMF_KEYBOARD_LOCK_NUM = 1 << 0, /**< "Num" lock is active */
+ ECORE_IMF_KEYBOARD_LOCK_CAPS = 1 << 1, /**< "Caps" lock is active */
+ ECORE_IMF_KEYBOARD_LOCK_SCROLL = 1 << 2 /**< "Scroll" lock is active */
+} Ecore_IMF_Keyboard_Locks;
+
+/**
+ * @typedef Ecore_IMF_Mouse_Flags
+ * Type for Ecore_IMF mouse flags
+ */
+typedef enum
+{
+ ECORE_IMF_MOUSE_NONE = 0, /**< A single click */
+ ECORE_IMF_MOUSE_DOUBLE_CLICK = 1 << 0, /**< A double click */
+ ECORE_IMF_MOUSE_TRIPLE_CLICK = 1 << 1 /**< A triple click */
+} Ecore_IMF_Mouse_Flags;
+
+typedef enum
+{
+ ECORE_IMF_INPUT_MODE_ALPHA = 1 << 0,
+ ECORE_IMF_INPUT_MODE_NUMERIC = 1 << 1,
+ ECORE_IMF_INPUT_MODE_SPECIAL = 1 << 2,
+ ECORE_IMF_INPUT_MODE_HEXA = 1 << 3,
+ ECORE_IMF_INPUT_MODE_TELE = 1 << 4,
+ ECORE_IMF_INPUT_MODE_FULL = (ECORE_IMF_INPUT_MODE_ALPHA | ECORE_IMF_INPUT_MODE_NUMERIC | ECORE_IMF_INPUT_MODE_SPECIAL),
+ ECORE_IMF_INPUT_MODE_INVISIBLE = 1 << 29,
+ ECORE_IMF_INPUT_MODE_AUTOCAP = 1 << 30
+} Ecore_IMF_Input_Mode;
+
+/**
+ * @typedef Ecore_IMF_Preedit_Type
+ *
+ * Ecore IMF Preedit style types
+ *
+ * @see ecore_imf_context_preedit_string_with_attributes_get()
+ */
+typedef enum
+{
+ ECORE_IMF_PREEDIT_TYPE_NONE, /**< None style @since 1.1 */
+ ECORE_IMF_PREEDIT_TYPE_SUB1, /**< Substring style 1 @since 1.1 */
+ ECORE_IMF_PREEDIT_TYPE_SUB2, /**< Substring style 2 @since 1.1 */
+ ECORE_IMF_PREEDIT_TYPE_SUB3, /**< Substring style 3 @since 1.1 */
+ ECORE_IMF_PREEDIT_TYPE_SUB4, /**< Substring style 4 @since 1.8 */
+ ECORE_IMF_PREEDIT_TYPE_SUB5, /**< Substring style 5 @since 1.8 */
+ ECORE_IMF_PREEDIT_TYPE_SUB6, /**< Substring style 6 @since 1.8 */
+ ECORE_IMF_PREEDIT_TYPE_SUB7 /**< Substring style 7 @since 1.8 */
+} Ecore_IMF_Preedit_Type;
+
+/**
+ * @typedef Ecore_IMF_Autocapital_Type
+ *
+ * Autocapitalization Types.
+ *
+ * @see ecore_imf_context_autocapital_type_set()
+ */
+typedef enum
+{
+ ECORE_IMF_AUTOCAPITAL_TYPE_NONE, /**< No auto-capitalization when typing @since 1.1 */
+ ECORE_IMF_AUTOCAPITAL_TYPE_WORD, /**< Autocapitalize each word typed @since 1.1 */
+ ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE, /**< Autocapitalize the start of each sentence @since 1.1 */
+ ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER, /**< Autocapitalize all letters @since 1.1 */
+} Ecore_IMF_Autocapital_Type;
+
+/**
+ * @typedef Ecore_IMF_Input_Panel_Layout
+ *
+ * Input panel (virtual keyboard) layout types.
+ *
+ * @see ecore_imf_context_input_panel_layout_set()
+ */
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL, /**< Default layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER, /**< Number layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL, /**< Email layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_URL, /**< URL layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER, /**< Phone Number layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_IP, /**< IP layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH, /**< Month layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY, /**< Number Only layout */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID, /**< Never use this */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_HEX, /**< Hexadecimal layout @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL, /**< Command-line terminal layout including esc, alt, ctrl key, so on (no auto-correct, no auto-capitalization) @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD /**< Like normal, but no auto-correct, no auto-capitalization etc. @since 1.2 */
+} Ecore_IMF_Input_Panel_Layout;
+
+/**
+ * @typedef Ecore_IMF_Input_Panel_Lang
+ *
+ * Input panel (virtual keyboard) language modes.
+ *
+ * @see ecore_imf_context_input_panel_language_set()
+ */
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC, /**< Automatic @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_LANG_ALPHABET /**< Alphabet @since 1.2 */
+} Ecore_IMF_Input_Panel_Lang;
+
+/**
+ * @typedef Ecore_IMF_Input_Panel_Return_Key_Type
+ *
+ * "Return" Key types on the input panel (virtual keyboard).
+ *
+ * @see ecore_imf_context_input_panel_return_key_type_set()
+ */
+typedef enum
+{
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT, /**< Default @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE, /**< Done @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO, /**< Go @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN, /**< Join @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN, /**< Login @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT, /**< Next @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH, /**< Search or magnifier icon @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND, /**< Send @since 1.2 */
+ ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN /**< Sign-in @since 1.8 */
+} Ecore_IMF_Input_Panel_Return_Key_Type;
+
+struct _Ecore_IMF_Event_Preedit_Start
+{
+ Ecore_IMF_Context *ctx;
+};
+
+struct _Ecore_IMF_Event_Preedit_End
+{
+ Ecore_IMF_Context *ctx;
+};
+
+struct _Ecore_IMF_Event_Preedit_Changed
+{
+ Ecore_IMF_Context *ctx;
+};
+
+struct _Ecore_IMF_Event_Commit
+{
+ Ecore_IMF_Context *ctx;
+ char *str;
+};
+
+struct _Ecore_IMF_Event_Delete_Surrounding
+{
+ Ecore_IMF_Context *ctx;
+ int offset;
+ int n_chars;
+};
+
+struct _Ecore_IMF_Event_Mouse_Down
+{
+ int button; /**< The button which has been pressed */
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ Ecore_IMF_Mouse_Flags flags; /**< The flags corresponding the mouse click (single, double or triple click) */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Mouse_Up
+{
+ int button; /**< The button which has been pressed */
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ Ecore_IMF_Mouse_Flags flags; /**< The flags corresponding the mouse click (single, double or triple click) */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Mouse_In
+{
+ int buttons;
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Mouse_Out
+{
+ int buttons;
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Mouse_Move
+{
+ int buttons;
+ struct {
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ } cur, prev;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Mouse_Wheel
+{
+ int direction; /* 0 = default up/down wheel */
+ int z; /* ...,-2,-1 = down, 1,2,... = up */
+ struct {
+ int x, y;
+ } output;
+ struct {
+ int x, y;
+ } canvas;
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Key_Down
+{
+ const char *keyname; /**< The string name of the key pressed */
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ const char *key; /**< The logical key : (eg shift+1 == exclamation) */
+ const char *string; /**< A UTF8 string if this keystroke has produced a visible string to be ADDED */
+ const char *compose; /**< A UTF8 string if this keystroke has modified a string in the middle of being composed - this string replaces the previous one */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+struct _Ecore_IMF_Event_Key_Up
+{
+ const char *keyname; /**< The string name of the key pressed */
+ Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */
+ Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */
+ const char *key; /**< The logical key : (eg shift+1 == exclamation) */
+ const char *string; /**< A UTF8 string if this keystroke has produced a visible string to be ADDED */
+ const char *compose; /**< A UTF8 string if this keystroke has modified a string in the middle of being composed - this string replaces the previous one */
+ unsigned int timestamp; /**< The timestamp when the event occurred */
+};
+
+union _Ecore_IMF_Event
+{
+ Ecore_IMF_Event_Mouse_Down mouse_down;
+ Ecore_IMF_Event_Mouse_Up mouse_up;
+ Ecore_IMF_Event_Mouse_In mouse_in;
+ Ecore_IMF_Event_Mouse_Out mouse_out;
+ Ecore_IMF_Event_Mouse_Move mouse_move;
+ Ecore_IMF_Event_Mouse_Wheel mouse_wheel;
+ Ecore_IMF_Event_Key_Down key_down;
+ Ecore_IMF_Event_Key_Up key_up;
+};
+
+struct _Ecore_IMF_Preedit_Attr
+{
+ Ecore_IMF_Preedit_Type preedit_type; /**< preedit style type */
+ unsigned int start_index; /**< start index of the range (in bytes) */
+ unsigned int end_index; /**< end index of the range (in bytes) */
+};
+
+struct _Ecore_IMF_Context_Class
+{
+ void (*add) (Ecore_IMF_Context *ctx);
+ void (*del) (Ecore_IMF_Context *ctx);
+ void (*client_window_set) (Ecore_IMF_Context *ctx, void *window);
+ void (*client_canvas_set) (Ecore_IMF_Context *ctx, void *canvas);
+ void (*show) (Ecore_IMF_Context *ctx);
+ void (*hide) (Ecore_IMF_Context *ctx);
+ void (*preedit_string_get) (Ecore_IMF_Context *ctx, char **str, int *cursor_pos);
+ void (*focus_in) (Ecore_IMF_Context *ctx);
+ void (*focus_out) (Ecore_IMF_Context *ctx);
+ void (*reset) (Ecore_IMF_Context *ctx);
+ void (*cursor_position_set) (Ecore_IMF_Context *ctx, int cursor_pos);
+ void (*use_preedit_set) (Ecore_IMF_Context *ctx, Eina_Bool use_preedit);
+ void (*input_mode_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode);
+ Eina_Bool (*filter_event) (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event);
+ void (*preedit_string_with_attributes_get) (Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos);
+ void (*prediction_allow_set)(Ecore_IMF_Context *ctx, Eina_Bool prediction);
+ void (*autocapital_type_set)(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type);
+ void (*control_panel_show) (Ecore_IMF_Context *ctx);
+ void (*control_panel_hide) (Ecore_IMF_Context *ctx);
+ void (*input_panel_layout_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout);
+ Ecore_IMF_Input_Panel_Layout (*input_panel_layout_get) (Ecore_IMF_Context *ctx);
+ void (*input_panel_language_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang);
+ Ecore_IMF_Input_Panel_Lang (*input_panel_language_get) (Ecore_IMF_Context *ctx);
+ void (*cursor_location_set) (Ecore_IMF_Context *ctx, int x, int y, int w, int h);
+ void (*input_panel_imdata_set)(Ecore_IMF_Context *ctx, const void* data, int len);
+ void (*input_panel_imdata_get)(Ecore_IMF_Context *ctx, void* data, int *len);
+ void (*input_panel_return_key_type_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type);
+ void (*input_panel_return_key_disabled_set) (Ecore_IMF_Context *ctx, Eina_Bool disabled);
+ void (*input_panel_caps_lock_mode_set) (Ecore_IMF_Context *ctx, Eina_Bool mode);
+ void (*input_panel_geometry_get)(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h);
+ Ecore_IMF_Input_Panel_State (*input_panel_state_get) (Ecore_IMF_Context *ctx);
+ void (*input_panel_event_callback_add) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value), void *data);
+ void (*input_panel_event_callback_del) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value));
+ void (*input_panel_language_locale_get) (Ecore_IMF_Context *ctx, char **lang);
+ void (*candidate_panel_geometry_get)(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h);
+};
+
+struct _Ecore_IMF_Context_Info
+{
+ const char *id; /* ID */
+ const char *description; /* Human readable description */
+ const char *default_locales; /* Languages for which this context is the default, separated by : */
+ const char *canvas_type; /* The canvas type used by the input method. Eg.: evas */
+ int canvas_required; /* Whether the canvas usage is required for this input method */
+};
+
+/**
+ * @}
+ */
+
+EAPI int ecore_imf_init(void);
+EAPI int ecore_imf_shutdown(void);
+
+EAPI void ecore_imf_module_register(const Ecore_IMF_Context_Info *info, Ecore_IMF_Context *(*imf_module_create)(void), Ecore_IMF_Context *(*imf_module_exit)(void));
+
+EAPI Eina_List *ecore_imf_context_available_ids_get(void);
+EAPI Eina_List *ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type);
+EAPI const char *ecore_imf_context_default_id_get(void);
+EAPI const char *ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type);
+EAPI const Ecore_IMF_Context_Info *ecore_imf_context_info_by_id_get(const char *id);
+
+EAPI Ecore_IMF_Context *ecore_imf_context_add(const char *id);
+EAPI const Ecore_IMF_Context_Info *ecore_imf_context_info_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_del(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window);
+EAPI void *ecore_imf_context_client_window_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas);
+EAPI void *ecore_imf_context_client_canvas_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_show(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_hide(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos);
+EAPI void ecore_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos);
+EAPI void ecore_imf_context_focus_in(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_focus_out(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_reset(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos);
+EAPI void ecore_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h);
+EAPI void ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit);
+EAPI void ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, Eina_Bool (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data);
+EAPI void ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode);
+EAPI Ecore_IMF_Input_Mode ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx);
+EAPI Eina_Bool ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event);
+
+/* plugin specific functions */
+EAPI Ecore_IMF_Context *ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc);
+EAPI void ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data);
+EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx);
+EAPI Eina_Bool ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
+EAPI void ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str);
+EAPI void ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars);
+EAPI void ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data);
+EAPI void *ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func);
+EAPI void ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info);
+EAPI void ecore_imf_context_prediction_allow_set(Ecore_IMF_Context *ctx, Eina_Bool prediction);
+EAPI Eina_Bool ecore_imf_context_prediction_allow_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_autocapital_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type);
+EAPI Ecore_IMF_Autocapital_Type ecore_imf_context_autocapital_type_get(Ecore_IMF_Context *ctx);
+
+EAPI void ecore_imf_context_control_panel_show(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_control_panel_hide(Ecore_IMF_Context *ctx);
+
+EAPI void ecore_imf_context_input_panel_show(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_hide(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_layout_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout);
+EAPI Ecore_IMF_Input_Panel_Layout ecore_imf_context_input_panel_layout_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_language_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang);
+EAPI Ecore_IMF_Input_Panel_Lang ecore_imf_context_input_panel_language_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_enabled_set(Ecore_IMF_Context *ctx, Eina_Bool enable);
+EAPI Eina_Bool ecore_imf_context_input_panel_enabled_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int len);
+EAPI void ecore_imf_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *len);
+EAPI void ecore_imf_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type);
+EAPI Ecore_IMF_Input_Panel_Return_Key_Type ecore_imf_context_input_panel_return_key_type_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx, Eina_Bool disabled);
+EAPI Eina_Bool ecore_imf_context_input_panel_return_key_disabled_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_caps_lock_mode_set(Ecore_IMF_Context *ctx, Eina_Bool mode);
+EAPI Eina_Bool ecore_imf_context_input_panel_caps_lock_mode_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h);
+EAPI Ecore_IMF_Input_Panel_State ecore_imf_context_input_panel_state_get(Ecore_IMF_Context *ctx);
+EAPI void ecore_imf_context_input_panel_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value), const void *data);
+EAPI void ecore_imf_context_input_panel_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value));
+EAPI void ecore_imf_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx, char **lang);
+EAPI void ecore_imf_context_candidate_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h);
+
+/* The following entry points must be exported by each input method module
+ */
+
+/*
+ * int imf_module_init (const Ecore_IMF_Context_Info **info);
+ * void imf_module_exit (void);
+ * Ecore_IMF_Context *imf_module_create (void);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_imf/Ecore_IMF_Evas.h b/src/lib/ecore_imf/Ecore_IMF_Evas.h
new file mode 100644
index 0000000000..5f7cdb90f3
--- /dev/null
+++ b/src/lib/ecore_imf/Ecore_IMF_Evas.h
@@ -0,0 +1,50 @@
+#ifndef _ECORE_IMF_EVAS_H
+#define _ECORE_IMF_EVAS_H
+
+#include <Ecore_IMF.h>
+#include <Evas.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_IMF_EVAS_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_IMF_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EAPI void ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event, Ecore_IMF_Event_Mouse_In *imf_event);
+EAPI void ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event, Ecore_IMF_Event_Mouse_Out *imf_event);
+EAPI void ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event, Ecore_IMF_Event_Mouse_Move *imf_event);
+EAPI void ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event, Ecore_IMF_Event_Mouse_Down *imf_event);
+EAPI void ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event, Ecore_IMF_Event_Mouse_Up *imf_event);
+EAPI void ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event, Ecore_IMF_Event_Mouse_Wheel *imf_event);
+EAPI void ecore_imf_evas_event_key_down_wrap(Evas_Event_Key_Down *evas_event, Ecore_IMF_Event_Key_Down *imf_event);
+EAPI void ecore_imf_evas_event_key_up_wrap(Evas_Event_Key_Up *evas_event, Ecore_IMF_Event_Key_Up *imf_event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_imf/ecore_imf.c b/src/lib/ecore_imf/ecore_imf.c
new file mode 100644
index 0000000000..7cf8a4a9f6
--- /dev/null
+++ b/src/lib/ecore_imf/ecore_imf.c
@@ -0,0 +1,73 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Ecore.h>
+#include <ecore_private.h>
+
+#include "Ecore_IMF.h"
+#include "ecore_imf_private.h"
+
+EAPI int ECORE_IMF_EVENT_PREEDIT_START = 0;
+EAPI int ECORE_IMF_EVENT_PREEDIT_END = 0;
+EAPI int ECORE_IMF_EVENT_PREEDIT_CHANGED = 0;
+EAPI int ECORE_IMF_EVENT_COMMIT = 0;
+EAPI int ECORE_IMF_EVENT_DELETE_SURROUNDING = 0;
+
+int _ecore_imf_log_dom = -1;
+static int _ecore_imf_init_count = 0;
+
+/**
+ * @defgroup Ecore_IMF_Lib_Group Ecore Input Method Library Functions
+ *
+ * Utility functions that set up and shut down the Ecore Input Method
+ * library.
+ */
+
+/**
+ * Initialises the Ecore_IMF library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ * @ingroup Ecore_IMF_Lib_Group
+ */
+EAPI int
+ecore_imf_init(void)
+{
+ if (++_ecore_imf_init_count != 1) return _ecore_imf_init_count;
+
+ if (!ecore_init()) return --_ecore_imf_init_count;
+ _ecore_imf_log_dom = eina_log_domain_register
+ ("ecore_imf", ECORE_IMF_DEFAULT_LOG_COLOR);
+ if (_ecore_imf_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the Ecore IMF module.");
+ ecore_shutdown();
+ return --_ecore_imf_init_count;
+ }
+ ecore_imf_module_init();
+
+ ECORE_IMF_EVENT_PREEDIT_START = ecore_event_type_new();
+ ECORE_IMF_EVENT_PREEDIT_END = ecore_event_type_new();
+ ECORE_IMF_EVENT_PREEDIT_CHANGED = ecore_event_type_new();
+ ECORE_IMF_EVENT_COMMIT = ecore_event_type_new();
+ ECORE_IMF_EVENT_DELETE_SURROUNDING = ecore_event_type_new();
+
+ return _ecore_imf_init_count;
+}
+
+/**
+ * Shuts down the Ecore_IMF library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ * @ingroup Ecore_IMF_Lib_Group
+ */
+EAPI int
+ecore_imf_shutdown(void)
+{
+ if (--_ecore_imf_init_count != 0) return _ecore_imf_init_count;
+ ecore_imf_module_shutdown();
+ eina_log_domain_unregister(_ecore_imf_log_dom);
+ _ecore_imf_log_dom = -1;
+ ecore_shutdown();
+ return _ecore_imf_init_count;
+}
diff --git a/src/lib/ecore_imf/ecore_imf_context.c b/src/lib/ecore_imf/ecore_imf_context.c
new file mode 100644
index 0000000000..3faa5acbd5
--- /dev/null
+++ b/src/lib/ecore_imf/ecore_imf_context.c
@@ -0,0 +1,1900 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+#include <Ecore.h>
+#include <ecore_private.h>
+
+#include "Ecore_IMF.h"
+#include "ecore_imf_private.h"
+
+/**
+ * @defgroup Ecore_IMF_Context_Group Ecore Input Method Context Functions
+ *
+ * Functions that operate on Ecore Input Method Context objects.
+
+ * Ecore Input Method Context Function defines the interface for EFL input methods.
+ * An input method is used by EFL text input widgets like elm_entry
+ * (based on edje_entry) to map from key events to Unicode character strings.
+ *
+ * The default input method can be set through setting the ECORE_IMF_MODULE environment variable.
+ *
+ * An input method may consume multiple key events in sequence and finally output the composed result.
+ * This is called preediting, and an input method may provide feedback about
+ * this process by displaying the intermediate composition states as preedit text.
+ *
+ * Immodule is plugin to connect your application and input method framework such as SCIM, ibus, and so on.@n
+ * ecore_imf_init() should be called to initialize and load immodule.@n
+ * ecore_imf_shutdown() is used for shutdowning and unloading immodule.
+ *
+ * An example of usage of these functions can be found at:
+ * @li @ref ecore_imf_example_c
+ */
+
+/**
+ * Get the list of the available Input Method Context ids.
+ *
+ * Note that the caller is responsible for freeing the Eina_List
+ * when finished with it. There is no need to finish the list strings.
+ *
+ * @return Return an Eina_List of strings;
+ * on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI Eina_List *
+ecore_imf_context_available_ids_get(void)
+{
+ return ecore_imf_module_context_ids_get();
+}
+
+EAPI Eina_List *
+ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type)
+{
+ return ecore_imf_module_context_ids_by_canvas_type_get(canvas_type);
+}
+
+/*
+ * Match @locale against @against.
+ *
+ * 'en_US' against 'en_US' => 4
+ * 'en_US' against 'en' => 3
+ * 'en', 'en_UK' against 'en_US' => 2
+ * all locales, against '*' => 1
+ */
+static int
+_ecore_imf_context_match_locale(const char *locale, const char *against, int against_len)
+{
+ if (strcmp(against, "*") == 0)
+ return 1;
+
+ if (strcasecmp(locale, against) == 0)
+ return 4;
+
+ if (strncasecmp(locale, against, 2) == 0)
+ return (against_len == 2) ? 3 : 2;
+
+ return 0;
+}
+
+/**
+ * Get the id of the default Input Method Context.
+ * The id may to used to create a new instance of an Input Method
+ * Context object.
+ *
+ * @return Return a string containing the id of the default Input
+ * Method Context; on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI const char *
+ecore_imf_context_default_id_get(void)
+{
+ return ecore_imf_context_default_id_by_canvas_type_get(NULL);
+}
+
+EAPI const char *
+ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type)
+{
+ const char *id;
+ Eina_List *modules;
+ Ecore_IMF_Module *module;
+ char *locale;
+ char *tmp;
+ int best_goodness = 0;
+
+ id = getenv("ECORE_IMF_MODULE");
+ if (id)
+ {
+ if (strcmp(id, "none") == 0) return NULL;
+ if (ecore_imf_module_get(id)) return id;
+ }
+
+ modules = ecore_imf_module_available_get();
+ if (!modules) return NULL;
+
+ locale = setlocale(LC_CTYPE, NULL);
+ if (!locale) return NULL;
+
+ locale = strdup(locale);
+
+ tmp = strchr(locale, '.');
+ if (tmp) *tmp = '\0';
+ tmp = strchr(locale, '@');
+ if (tmp) *tmp = '\0';
+
+ id = NULL;
+
+ EINA_LIST_FREE(modules, module)
+ {
+ if (canvas_type &&
+ strcmp(module->info->canvas_type, canvas_type) == 0)
+ continue;
+
+ const char *p = module->info->default_locales;
+ while (p)
+ {
+ const char *q = strchr(p, ':');
+ int goodness = _ecore_imf_context_match_locale(locale, p, q ? (size_t)(q - p) : strlen (p));
+
+ if (goodness > best_goodness)
+ {
+ id = module->info->id;
+ best_goodness = goodness;
+ }
+
+ p = q ? q + 1 : NULL;
+ }
+ }
+
+ free(locale);
+ return id;
+}
+
+/**
+ * Retrieve the info for the Input Method Context with @p id.
+ *
+ * @param id The Input Method Context id to query for.
+ * @return Return a #Ecore_IMF_Context_Info for the Input Method Context with @p id;
+ * on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ *
+ * const char *ctx_id;
+ * const Ecore_IMF_Context_Info *ctx_info;
+ * Ecore_IMF_Context *imf_context;
+ * ctx_id = ecore_imf_context_default_id_get();
+ * if (ctx_id)
+ * {
+ * ctx_info = ecore_imf_context_info_by_id_get(ctx_id);
+ * if (!ctx_info->canvas_type ||
+ * strcmp(ctx_info->canvas_type, "evas") == 0)
+ * {
+ * imf_context = ecore_imf_context_add(ctx_id);
+ * }
+ * else
+ * {
+ * ctx_id = ecore_imf_context_default_id_by_canvas_type_get("evas");
+ * if (ctx_id)
+ * {
+ * imf_context = ecore_imf_context_add(ctx_id);
+ * }
+ * }
+ * }
+ * @endcode
+ */
+EAPI const Ecore_IMF_Context_Info *
+ecore_imf_context_info_by_id_get(const char *id)
+{
+ Ecore_IMF_Module *module;
+
+ if (!id) return NULL;
+ module = ecore_imf_module_get(id);
+ if (!module) return NULL;
+ return module->info;
+}
+
+/**
+ * Create a new Input Method Context defined by the given id.
+ *
+ * @param id The Input Method Context id.
+ * @return A newly allocated Input Method Context;
+ * on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI Ecore_IMF_Context *
+ecore_imf_context_add(const char *id)
+{
+ Ecore_IMF_Context *ctx;
+
+ if (!id) return NULL;
+ ctx = ecore_imf_module_context_create(id);
+ if (!ctx || !ctx->klass) return NULL;
+ if (ctx->klass->add) ctx->klass->add(ctx);
+ /* default use_preedit is EINA_TRUE, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_use_preedit_set(ctx, EINA_TRUE);
+
+ /* default prediction is EINA_TRUE, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_prediction_allow_set(ctx, EINA_TRUE);
+
+ /* default autocapital type is SENTENCE type, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_autocapital_type_set(ctx, ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
+
+ /* default input panel enabled status is EINA_TRUE, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_input_panel_enabled_set(ctx, EINA_TRUE);
+
+ /* default input panel layout type is NORMAL type, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_input_panel_layout_set(ctx, ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL);
+
+ /* default input_mode is ECORE_IMF_INPUT_MODE_FULL, so let's make sure it's
+ * set on the immodule */
+ ecore_imf_context_input_mode_set(ctx, ECORE_IMF_INPUT_MODE_FULL);
+ return ctx;
+}
+
+/**
+ * Retrieve the info for the given Input Method Context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return Return a #Ecore_IMF_Context_Info for the given Input Method Context;
+ * on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI const Ecore_IMF_Context_Info *
+ecore_imf_context_info_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_info_get");
+ return NULL;
+ }
+ return ctx->module->info;
+}
+
+/**
+ * Delete the given Input Method Context and free its memory.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_del(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Func_Node *fn;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_del");
+ return;
+ }
+ if (ctx->klass->del) ctx->klass->del(ctx);
+
+ if (ctx->callbacks)
+ {
+ EINA_LIST_FREE(ctx->callbacks, fn)
+ free(fn);
+ }
+
+ ECORE_MAGIC_SET(ctx, ECORE_MAGIC_NONE);
+ free(ctx);
+}
+
+/**
+ * Set the client window for the Input Method Context; this is the
+ * Ecore_X_Window when using X11, Ecore_Win32_Window when using Win32, etc.
+ * This window is used in order to correctly position status windows, and may
+ * also be used for purposes internal to the Input Method Context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param window The client window. This may be @c NULL to indicate
+ * that the previous client window no longer exists.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_client_window_set");
+ return;
+ }
+ if (ctx->klass->client_window_set) ctx->klass->client_window_set(ctx, window);
+ ctx->window = window;
+}
+
+/**
+ * Get the client window of the Input Method Context
+ *
+ * See @ref ecore_imf_context_client_window_set for more details.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return Return the client window.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void *
+ecore_imf_context_client_window_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_client_window_get");
+ return NULL;
+ }
+ return ctx->window;
+}
+
+/**
+ * Set the client canvas for the Input Method Context; this is the
+ * canvas in which the input appears.
+ * The canvas type can be determined by using the context canvas type.
+ * Actually only canvas with type "evas" (Evas *) is supported.
+ * This canvas may be used in order to correctly position status windows, and may
+ * also be used for purposes internal to the Input Method Context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param canvas The client canvas. This may be @c NULL to indicate
+ * that the previous client canvas no longer exists.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_client_canvas_set");
+ return;
+ }
+ if (ctx->klass->client_canvas_set) ctx->klass->client_canvas_set(ctx, canvas);
+ ctx->client_canvas = canvas;
+}
+
+/**
+ * Get the client canvas of the Input Method Context.
+ *
+ * See @ref ecore_imf_context_client_canvas_set for more details.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return Return the client canvas.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void *
+ecore_imf_context_client_canvas_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_client_canvas_get");
+ return NULL;
+ }
+ return ctx->client_canvas;
+}
+
+/**
+ * Ask the Input Method Context to show itself.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_show(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_show");
+ return;
+ }
+ if (ctx->klass->show) ctx->klass->show(ctx);
+}
+
+/**
+ * Ask the Input Method Context to hide itself.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_hide(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_hide");
+ return;
+ }
+ if (ctx->klass->hide) ctx->klass->hide(ctx);
+}
+
+/**
+ * Retrieve the current preedit string and cursor position
+ * for the Input Method Context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param str Location to store the retrieved string. The
+ * string retrieved must be freed with free().
+ * @param cursor_pos Location to store position of cursor (in characters)
+ * within the preedit string.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_preedit_string_get");
+ return;
+ }
+ if (ctx->klass->preedit_string_get)
+ ctx->klass->preedit_string_get(ctx, str, cursor_pos);
+ else
+ {
+ if (str) *str = strdup("");
+ if (cursor_pos) *cursor_pos = 0;
+ }
+}
+
+/**
+ * Retrieve the current preedit string, attributes and
+ * cursor position for the Input Method Context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param str Location to store the retrieved string. The
+ * string retrieved must be freed with free().
+ * @param attrs an Eina_List of attributes
+ * @param cursor_pos Location to store position of cursor (in characters)
+ * within the preedit string.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ * char *preedit_string;
+ * int cursor_pos;
+ * Eina_List *attrs = NULL, *l = NULL;
+ * Ecore_IMF_Preedit_Attr *attr;
+ *
+ * ecore_imf_context_preedit_string_with_attributes_get(imf_context,
+ * &preedit_string,
+ * &attrs, &cursor_pos);
+ * if (!preedit_string) return;
+ *
+ * if (strlen(preedit_string) > 0)
+ * {
+ * if (attrs)
+ * {
+ * EINA_LIST_FOREACH(attrs, l, attr)
+ * {
+ * if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB1)
+ * {
+ * // Something to do
+ * }
+ * else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB2)
+ * {
+ * // Something to do
+ * }
+ * else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3)
+ * {
+ * // Something to do
+ * }
+ * }
+ * }
+ * }
+ *
+ * // delete attribute list
+ * EINA_LIST_FREE(attrs, attr) free(attr);
+ *
+ * free(preedit_string);
+ * @endcode
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_preedit_string_with_attributes_get");
+ return;
+ }
+ if (ctx->klass->preedit_string_with_attributes_get)
+ ctx->klass->preedit_string_with_attributes_get(ctx, str, attrs, cursor_pos);
+ else
+ {
+ if (str) *str = strdup("");
+ if (attrs) *attrs = NULL;
+ if (cursor_pos) *cursor_pos = 0;
+ }
+}
+
+/**
+ * Notify the Input Method Context that the widget to which its
+ * correspond has gained focus.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _focus_in_cb(void *data, Evas_Object *o, const char *emission, const char *source)
+ * {
+ * ecore_imf_context_reset(imf_context);
+ * ecore_imf_context_focus_in(imf_context);
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_IN, _focus_in_cb, ed);
+ * @endcode
+ */
+EAPI void
+ecore_imf_context_focus_in(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_focus_in");
+ return;
+ }
+ if (ctx->klass->focus_in) ctx->klass->focus_in(ctx);
+}
+
+/**
+ * Notify the Input Method Context that the widget to which its
+ * correspond has lost focus.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _focus_out_cb(void *data, Evas_Object *o, const char *emission, const char *source)
+ * {
+ * ecore_imf_context_reset(imf_context);
+ * ecore_imf_context_focus_out(imf_context);
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT, _focus_out_cb, ed);
+ * @endcode
+ */
+EAPI void
+ecore_imf_context_focus_out(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_focus_out");
+ return;
+ }
+ if (ctx->klass->focus_out) ctx->klass->focus_out(ctx);
+}
+
+/**
+ * Notify the Input Method Context that a change such as a
+ * change in cursor position has been made. This will typically
+ * cause the Input Method Context to clear the preedit state.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _focus_out_cb(void *data, Evas_Object *o, const char *emission, const char *source)
+ * {
+ * ecore_imf_context_reset(imf_context);
+ * ecore_imf_context_focus_out(imf_context);
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT, _focus_out_cb, ed);
+ * @endcode
+ */
+EAPI void
+ecore_imf_context_reset(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_reset");
+ return;
+ }
+ if (ctx->klass->reset) ctx->klass->reset(ctx);
+}
+
+/**
+ * Notify the Input Method Context that a change in the cursor
+ * position has been made.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param cursor_pos New cursor position in characters.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_cursor_position_set");
+ return;
+ }
+ if (ctx->klass->cursor_position_set) ctx->klass->cursor_position_set(ctx, cursor_pos);
+}
+
+/**
+ * Notify the Input Method Context that a change in the cursor
+ * location has been made. The location is relative to the canvas.
+ * The cursor location can be used to determine the position of
+ * candidate word window in the immodule.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param x cursor x position.
+ * @param y cursor y position.
+ * @param w cursor width.
+ * @param h cursor height.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_cursor_location_set");
+ return;
+ }
+ if (ctx->klass->cursor_location_set) ctx->klass->cursor_location_set(ctx, x, y, w, h);
+}
+
+/**
+ * Set whether the IM context should use the preedit string
+ * to display feedback. If @c use_preedit is @c EINA_FALSE (default
+ * is @c EINA_TRUE), then the IM context may use some other method to display
+ * feedback, such as displaying it in a child of the root window.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param use_preedit Whether the IM context should use the preedit string.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_use_preedit_set");
+ return;
+ }
+ if (ctx->klass->use_preedit_set) ctx->klass->use_preedit_set(ctx, use_preedit);
+}
+
+/**
+ * Set whether the IM context should allow to use the text prediction.
+ * If @p prediction is @c EINA_FALSE (default is @c EINA_TRUE), then the IM
+ * context will not display the text prediction window.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param prediction Whether the IM context should allow to use the text prediction.
+ * @note Default value is EINA_TRUE.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_prediction_allow_set(Ecore_IMF_Context *ctx, Eina_Bool prediction)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_prediction_allow_set");
+ return;
+ }
+
+ ctx->allow_prediction = prediction;
+
+ if (ctx->klass->prediction_allow_set)
+ ctx->klass->prediction_allow_set(ctx, prediction);
+}
+
+/**
+ * Get whether the IM context should allow to use the text prediction.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return @c EINA_TRUE if it allows to use the text prediction, otherwise
+ * @c EINA_FALSE.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI Eina_Bool
+ecore_imf_context_prediction_allow_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_prediction_allow_get");
+ return EINA_FALSE;
+ }
+
+ return ctx->allow_prediction;
+}
+
+/**
+ * Set the autocapitalization type on the immodule.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param autocapital_type the autocapitalization type.
+ * @note Default type is ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_autocapital_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_autocapital_type_set");
+ return;
+ }
+
+ ctx->autocapital_type = autocapital_type;
+
+ if (ctx->klass->autocapital_type_set) ctx->klass->autocapital_type_set(ctx, autocapital_type);
+}
+
+/**
+ * Get the autocapitalization type.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return The autocapital type being used by @p ctx.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI Ecore_IMF_Autocapital_Type
+ecore_imf_context_autocapital_type_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_autocapital_allow_get");
+ return ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
+ }
+
+ return ctx->autocapital_type;
+}
+
+/**
+ * Set the callback to be used on surrounding_get request.
+ *
+ * This callback will be called when the Input Method Context
+ * module requests the surrounding context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param func The callback to be called.
+ * @param data The data pointer to be passed to @p func
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, Eina_Bool (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_retrieve_surrounding_callback_set");
+ return;
+ }
+
+ ctx->retrieve_surrounding_func = func;
+ ctx->retrieve_surrounding_data = (void *) data;
+}
+
+/**
+ * Set the input mode used by the Ecore Input Context.
+ *
+ * The input mode can be one of the input modes defined in
+ * Ecore_IMF_Input_Mode. The default input mode is
+ * ECORE_IMF_INPUT_MODE_FULL.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param input_mode The input mode to be used by @p ctx.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI void
+ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_mode_set");
+ return;
+ }
+ if (ctx->klass->input_mode_set) ctx->klass->input_mode_set(ctx, input_mode);
+ ctx->input_mode = input_mode;
+}
+
+/**
+ * Get the input mode being used by the Ecore Input Context.
+ *
+ * See @ref ecore_imf_context_input_mode_set for more details.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return The input mode being used by @p ctx.
+ * @ingroup Ecore_IMF_Context_Group
+ */
+EAPI Ecore_IMF_Input_Mode
+ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_mode_set");
+ return 0;
+ }
+ return ctx->input_mode;
+}
+
+/**
+ * Allow an Ecore Input Context to internally handle an event.
+ * If this function returns @c EINA_TRUE, then no further processing
+ * should be done for this event.
+ *
+ * Input methods must be able to accept all types of events (simply
+ * returning @c EINA_FALSE if the event was not handled), but there is no
+ * obligation of any events to be submitted to this function.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param type The type of event defined by #Ecore_IMF_Event_Type.
+ * @param event The event itself.
+ * @return @c EINA_TRUE if the event was handled; otherwise @c EINA_FALSE.
+ * @ingroup Ecore_IMF_Context_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+ * {
+ * Evas_Event_Key_Down *ev = event_info;
+ * if (!ev->keyname) return;
+ *
+ * if (imf_context)
+ * {
+ * Ecore_IMF_Event_Key_Down ecore_ev;
+ * ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
+ * if (ecore_imf_context_filter_event(imf_context,
+ * ECORE_IMF_EVENT_KEY_DOWN,
+ * (Ecore_IMF_Event *)&ecore_ev))
+ * return;
+ * }
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, data);
+ * @endcode
+ */
+EAPI Eina_Bool
+ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_filter_event");
+ return EINA_FALSE;
+ }
+ if (ctx->klass->filter_event) return ctx->klass->filter_event(ctx, type, event);
+ return EINA_FALSE;
+}
+
+/**
+ * @defgroup Ecore_IMF_Context_Module_Group Ecore Input Method Context Module Functions
+ *
+ * Functions that should be used by Ecore Input Method Context modules.
+ */
+
+/**
+ * Creates a new Input Method Context with klass specified by @p ctxc.
+ *
+ * This method should be used by modules implementing the Input
+ * Method Context interface.
+ *
+ * @param ctxc An #Ecore_IMF_Context_Class.
+ * @return A new #Ecore_IMF_Context; on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI Ecore_IMF_Context *
+ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc)
+{
+ Ecore_IMF_Context *ctx;
+
+ if (!ctxc) return NULL;
+ ctx = calloc(1, sizeof(Ecore_IMF_Context));
+ if (!ctx) return NULL;
+ ECORE_MAGIC_SET(ctx, ECORE_MAGIC_CONTEXT);
+ ctx->klass = ctxc;
+ ctx->data = NULL;
+ ctx->retrieve_surrounding_func = NULL;
+ ctx->retrieve_surrounding_data = NULL;
+ return ctx;
+}
+
+/**
+ * Set the Input Method Context specific data.
+ *
+ * Note that this method should be used by modules to set
+ * the Input Method Context specific data and it's not meant to
+ * be used by applications to store application specific data.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param data The Input Method Context specific data.
+ * @return A new #Ecore_IMF_Context; on failure it returns NULL.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_data_set");
+ return;
+ }
+ ctx->data = data;
+}
+
+/**
+ * Get the Input Method Context specific data.
+ *
+ * See @ref ecore_imf_context_data_set for more details.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return The Input Method Context specific data.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_data_get");
+ return NULL;
+ }
+ return ctx->data;
+}
+
+/**
+ * Retrieve context around insertion point.
+ * Input methods typically want context in order to constrain input text based on existing text;
+ * this is important for languages such as Thai where only some sequences of characters are allowed.
+ * In addition, the text around the insertion point can be used for supporting autocapital feature.
+ *
+ * This function is implemented by calling the
+ * Ecore_IMF_Context::retrieve_surrounding_func (
+ * set using #ecore_imf_context_retrieve_surrounding_callback_set).
+ *
+ * There is no obligation for a widget to respond to the
+ * retrieve_surrounding_func, so input methods must be prepared
+ * to function without context.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param text Location to store a UTF-8 encoded string of text
+ * holding context around the insertion point.
+ * If the function returns @c EINA_TRUE, then you must free
+ * the result stored in this location with free().
+ * @param cursor_pos Location to store the position in characters of
+ * the insertion cursor within @p text.
+ * @return @c EINA_TRUE if surrounding text was provided; otherwise
+ * @c EINA_FALSE.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI Eina_Bool
+ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos)
+{
+ int result = EINA_FALSE;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_surrounding_get");
+ return EINA_FALSE;
+ }
+
+ if (ctx->retrieve_surrounding_func)
+ {
+ result = ctx->retrieve_surrounding_func(ctx->retrieve_surrounding_data, ctx, text, cursor_pos);
+ if (!result)
+ {
+ if (text) *text = NULL;
+ if (cursor_pos) *cursor_pos = 0;
+ }
+ }
+ return result;
+}
+
+static void
+_ecore_imf_event_free_preedit(void *data EINA_UNUSED, void *event)
+{
+ free(event);
+}
+
+/**
+ * Adds ECORE_IMF_EVENT_PREEDIT_START to the event queue.
+ *
+ * ECORE_IMF_EVENT_PREEDIT_START should be added when a new preedit sequence starts.
+ * It's asynchronous method to put event to the event queue.
+ * ecore_imf_context_event_callback_call() can be used as synchronous method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Event_Commit *ev;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_preedit_start_event_add");
+ return;
+ }
+
+ ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Start));
+ ev->ctx = ctx;
+ ecore_event_add(ECORE_IMF_EVENT_PREEDIT_START,
+ ev, _ecore_imf_event_free_preedit, NULL);
+}
+
+/**
+ * Adds ECORE_IMF_EVENT_PREEDIT_END to the event queue.
+ *
+ * ECORE_IMF_EVENT_PREEDIT_END should be added when a new preedit sequence has been completed or canceled.
+ * It's asynchronous method to put event to the event queue.
+ * ecore_imf_context_event_callback_call() can be used as synchronous method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Event_Commit *ev;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_preedit_end_event_add");
+ return;
+ }
+
+ ev = malloc(sizeof(Ecore_IMF_Event_Preedit_End));
+ ev->ctx = ctx;
+ ecore_event_add(ECORE_IMF_EVENT_PREEDIT_END,
+ ev, _ecore_imf_event_free_preedit, NULL);
+}
+
+/**
+ * Adds ECORE_IMF_EVENT_PREEDIT_CHANGED to the event queue.
+ *
+ * It's asynchronous method to put event to the event queue.
+ * ecore_imf_context_event_callback_call() can be used as synchronous method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Event_Commit *ev;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_preedit_changed_event_add");
+ return;
+ }
+
+ ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Changed));
+ ev->ctx = ctx;
+ ecore_event_add(ECORE_IMF_EVENT_PREEDIT_CHANGED,
+ ev, _ecore_imf_event_free_preedit, NULL);
+}
+
+static void
+_ecore_imf_event_free_commit(void *data EINA_UNUSED, void *event)
+{
+ Ecore_IMF_Event_Commit *ev;
+
+ ev = event;
+ if (ev->str) free(ev->str);
+ free(ev);
+}
+
+/**
+ * Adds ECORE_IMF_EVENT_COMMIT to the event queue.
+ *
+ * It's asynchronous method to put event to the event queue.
+ * ecore_imf_context_event_callback_call() can be used as synchronous method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param str The committed string.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str)
+{
+ Ecore_IMF_Event_Commit *ev;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_commit_event_add");
+ return;
+ }
+
+ ev = malloc(sizeof(Ecore_IMF_Event_Commit));
+ ev->ctx = ctx;
+ ev->str = str ? strdup(str) : NULL;
+ ecore_event_add(ECORE_IMF_EVENT_COMMIT,
+ ev, _ecore_imf_event_free_commit, NULL);
+
+}
+
+static void
+_ecore_imf_event_free_delete_surrounding(void *data EINA_UNUSED, void *event)
+{
+ free(event);
+}
+
+/**
+ * Adds ECORE_IMF_EVENT_DELETE_SURROUNDING to the event queue.
+ *
+ * Asks the widget that the input context is attached to to delete characters around the cursor position
+ * by adding the ECORE_IMF_EVENT_DELETE_SURROUNDING to the event queue.
+ * Note that offset and n_chars are in characters not in bytes.
+ *
+ * It's asynchronous method to put ECORE_IMF_EVENT_DELETE_SURROUNDING event to the event queue.
+ * ecore_imf_context_event_callback_call() can be used as synchronous method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param offset The start offset of surrounding to be deleted.
+ * @param n_chars The number of characters to be deleted.
+ * @ingroup Ecore_IMF_Context_Module_Group
+ */
+EAPI void
+ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars)
+{
+ Ecore_IMF_Event_Delete_Surrounding *ev;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_delete_surrounding_event_add");
+ return;
+ }
+
+ ev = malloc(sizeof(Ecore_IMF_Event_Delete_Surrounding));
+ ev->ctx = ctx;
+ ev->offset = offset;
+ ev->n_chars = n_chars;
+ ecore_event_add(ECORE_IMF_EVENT_DELETE_SURROUNDING,
+ ev, _ecore_imf_event_free_delete_surrounding, NULL);
+}
+
+/**
+ * Add (register) a callback function to a given context event.
+ *
+ * This function adds a function callback to the context @p ctx when the
+ * event of type @p type occurs on it. The function pointer is @p
+ * func.
+ *
+ * The event type @p type to trigger the function may be one of
+ * #ECORE_IMF_CALLBACK_PREEDIT_START, #ECORE_IMF_CALLBACK_PREEDIT_END,
+ * #ECORE_IMF_CALLBACK_PREEDIT_CHANGED, #ECORE_IMF_CALLBACK_COMMIT and
+ * #ECORE_IMF_CALLBACK_DELETE_SURROUNDING.
+ *
+ * @param ctx Ecore_IMF_Context to attach a callback to.
+ * @param type The type of event that will trigger the callback
+ * @param func The (callback) function to be called when the event is
+ * triggered
+ * @param data The data pointer to be passed to @p func
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ *
+ * Example
+ * @code
+ * static void
+ * _imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx, void *event_info)
+ * {
+ * char *commit_str = event_info;
+ * // something to do
+ * }
+ *
+ * ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _imf_event_commit_cb, data);
+ * @endcode
+ */
+EAPI void
+ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data)
+{
+ Ecore_IMF_Func_Node *fn = NULL;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_event_callback_add");
+ return;
+ }
+
+ if (!func) return;
+
+ fn = calloc(1, sizeof (Ecore_IMF_Func_Node));
+ if (!fn) return;
+
+ fn->func = func;
+ fn->data = data;
+ fn->type = type;
+
+ ctx->callbacks = eina_list_append(ctx->callbacks, fn);
+}
+
+/**
+ * Delete (unregister) a callback function registered to a given
+ * context event.
+ *
+ * This function removes a function callback from the context @p ctx when the
+ * event of type @p type occurs on it. The function pointer is @p
+ * func.
+ *
+ * @see ecore_imf_context_event_callback_add() for more details
+ *
+ * @param ctx Ecore_IMF_Context to remove a callback from.
+ * @param type The type of event that was triggering the callback
+ * @param func The (callback) function that was to be called when the event was triggered
+ * @return the data pointer
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void *
+ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func)
+{
+ Eina_List *l = NULL;
+ Eina_List *l_next = NULL;
+ Ecore_IMF_Func_Node *fn = NULL;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_event_callback_del");
+ return NULL;
+ }
+
+ if (!func) return NULL;
+ if (!ctx->callbacks) return NULL;
+
+ EINA_LIST_FOREACH_SAFE(ctx->callbacks, l, l_next, fn)
+ {
+ if ((fn) && (fn->func == func) && (fn->type == type))
+ {
+ void *tmp = (void *)fn->data;
+ free(fn);
+ ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
+ return tmp;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Call a given callback on the context @p ctx.
+ *
+ * ecore_imf_context_preedit_start_event_add(), ecore_imf_context_preedit_end_event_add(),
+ * ecore_imf_context_preedit_changed_event_add(), ecore_imf_context_commit_event_add() and
+ * ecore_imf_context_delete_surrounding_event_add() APIs are asynchronous
+ * because those API adds each event to the event queue.
+ *
+ * This API provides the way to call each callback function immediately.
+ *
+ * @param ctx Ecore_IMF_Context.
+ * @param type The type of event that will trigger the callback
+ * @param event_info The pointer to event specific struct or information to
+ * pass to the callback functions registered on this event
+ * @ingroup Ecore_IMF_Context_Module_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info)
+{
+ Ecore_IMF_Func_Node *fn = NULL;
+ Eina_List *l = NULL;
+
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_event_callback_call");
+ return;
+ }
+
+ EINA_LIST_FOREACH(ctx->callbacks, l, fn)
+ {
+ if ((fn) && (fn->type == type) && (fn->func))
+ fn->func(fn->data, ctx, event_info);
+ }
+}
+
+/**
+ * Ask the Input Method Context to show the control panel of using Input Method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_control_panel_show(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_control_panel_show");
+ return;
+ }
+
+ if (ctx->klass->control_panel_show) ctx->klass->control_panel_show(ctx);
+}
+
+/**
+ * Ask the Input Method Context to hide the control panel of using Input Method.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_control_panel_hide(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_control_panel_hide");
+ return;
+ }
+
+ if (ctx->klass->control_panel_hide) ctx->klass->control_panel_hide(ctx);
+}
+
+/**
+ * Ask the Input Method Context to show the input panel (virtual keyboard).
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_show");
+ return;
+ }
+
+ if (ctx->klass->show) ctx->klass->show(ctx);
+}
+
+/**
+ * Ask the Input Method Context to hide the input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_hide");
+ return;
+ }
+
+ if (ctx->klass->hide) ctx->klass->hide(ctx);
+}
+
+/**
+ * Set the layout of the input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param layout see #Ecore_IMF_Input_Panel_Layout
+ * @note Default layout type is ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_input_panel_layout_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_layout_set");
+ return;
+ }
+
+ if (ctx->klass->input_panel_layout_set)
+ ctx->klass->input_panel_layout_set(ctx, layout);
+
+ ctx->input_panel_layout = layout;
+}
+
+/**
+ * Get the layout of the current active input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return layout see #Ecore_IMF_Input_Panel_Layout
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI Ecore_IMF_Input_Panel_Layout
+ecore_imf_context_input_panel_layout_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_layout_get");
+ return ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID;
+ }
+
+ if (ctx->klass->input_panel_layout_get)
+ return ctx->input_panel_layout;
+ else
+ return ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID;
+}
+
+/**
+ * Set the language of the input panel.
+ * This API can be used when you want to show the English keyboard.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param lang the language to be set to the input panel.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_input_panel_language_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_language_set");
+ return;
+ }
+
+ if (ctx->klass->input_panel_language_set) ctx->klass->input_panel_language_set(ctx, lang);
+ ctx->input_panel_lang = lang;
+}
+
+/**
+ * Get the language of the input panel.
+ *
+ * See @ref ecore_imf_context_input_panel_language_set for more details.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return Ecore_IMF_Input_Panel_Lang
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI Ecore_IMF_Input_Panel_Lang
+ecore_imf_context_input_panel_language_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_language_get");
+ return ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC;
+ }
+
+ return ctx->input_panel_lang;
+}
+
+/**
+ * Set whether the Input Method Context should request to show the input panel automatically
+ * when the widget has focus.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param enabled If true, the input panel will be shown when the widget is clicked or has focus.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI void
+ecore_imf_context_input_panel_enabled_set(Ecore_IMF_Context *ctx,
+ Eina_Bool enabled)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_enabled_set");
+ return;
+ }
+
+ ctx->input_panel_enabled = enabled;
+}
+
+/**
+ * Get whether the Input Method Context requests to show the input panel automatically.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return Return the attribute to show the input panel automatically
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.1.0
+ */
+EAPI Eina_Bool
+ecore_imf_context_input_panel_enabled_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_enabled_get");
+ return EINA_FALSE;
+ }
+
+ return ctx->input_panel_enabled;
+}
+
+/**
+ * Set the input panel-specific data to deliver to the input panel.
+ * This API is used by applications to deliver specific data to the input panel.
+ * The data format MUST be negotiated by both application and the input panel.
+ * The size and format of data are defined by the input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param data The specific data to be set to the input panel.
+ * @param len the length of data, in bytes, to send to the input panel
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int len)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_imdata_set");
+ return;
+ }
+
+ if (!data) return;
+
+ if (ctx->klass->input_panel_imdata_set)
+ ctx->klass->input_panel_imdata_set(ctx, data, len);
+}
+
+/**
+ * Get the specific data of the current active input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param data The specific data to be got from the input panel
+ * @param len The length of data
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *len)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_imdata_get");
+ return;
+ }
+
+ if (!data) return;
+
+ if (ctx->klass->input_panel_imdata_get)
+ ctx->klass->input_panel_imdata_get(ctx, data, len);
+}
+
+/**
+ * Set the "return" key type. This type is used to set string or icon on the "return" key of the input panel.
+ *
+ * An input panel displays the string or icon associated with this type
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param return_key_type The type of "return" key on the input panel
+ * @note Default type is ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_return_key_type_set");
+ return;
+ }
+
+ ctx->input_panel_return_key_type = return_key_type;
+ if (ctx->klass->input_panel_return_key_type_set) ctx->klass->input_panel_return_key_type_set(ctx, return_key_type);
+}
+
+/**
+ * Get the "return" key type.
+ *
+ * @see ecore_imf_context_input_panel_return_key_type_set() for more details
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return The type of "return" key on the input panel
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI Ecore_IMF_Input_Panel_Return_Key_Type
+ecore_imf_context_input_panel_return_key_type_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_return_key_type_get");
+ return EINA_FALSE;
+ }
+
+ return ctx->input_panel_return_key_type;
+}
+
+/**
+ * Set the return key on the input panel to be disabled.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param disabled The state
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx, Eina_Bool disabled)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_return_key_disabled_set");
+ return;
+ }
+
+ ctx->input_panel_return_key_disabled = disabled;
+ if (ctx->klass->input_panel_return_key_disabled_set) ctx->klass->input_panel_return_key_disabled_set(ctx, disabled);
+}
+
+/**
+ * Get whether the return key on the input panel should be disabled or not.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return @c EINA_TRUE if it should be disabled.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI Eina_Bool
+ecore_imf_context_input_panel_return_key_disabled_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_return_key_disabled_get");
+ return EINA_FALSE;
+ }
+
+ return ctx->input_panel_return_key_disabled;
+}
+
+/**
+ * Set the caps lock mode on the input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param mode Turn on caps lock on the input panel if @c EINA_TRUE.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_input_panel_caps_lock_mode_set(Ecore_IMF_Context *ctx, Eina_Bool mode)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_caps_lock_mode_set");
+ return;
+ }
+
+ if (ctx->klass->input_panel_caps_lock_mode_set)
+ ctx->klass->input_panel_caps_lock_mode_set(ctx, mode);
+
+ ctx->input_panel_caps_lock_mode = mode;
+}
+
+/**
+ * Get the caps lock mode on the input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return @c EINA_TRUE if the caps lock is turned on.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.2.0
+ */
+EAPI Eina_Bool
+ecore_imf_context_input_panel_caps_lock_mode_get(Ecore_IMF_Context *ctx)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_caps_lock_mode_get");
+ return EINA_FALSE;
+ }
+
+ return ctx->input_panel_caps_lock_mode;
+}
+
+/**
+ * Get the position of the current active input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param x top-left x co-ordinate of the input panel
+ * @param y top-left y co-ordinate of the input panel
+ * @param w width of the input panel
+ * @param h height of the input panel
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI void
+ecore_imf_context_input_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_geometry_get");
+ return;
+ }
+
+ if (ctx->klass->input_panel_geometry_get)
+ ctx->klass->input_panel_geometry_get(ctx, x, y, w, h);
+}
+
+/**
+ * Get state of current active input panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @return The state of input panel.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI Ecore_IMF_Input_Panel_State
+ecore_imf_context_input_panel_state_get(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Input_Panel_State state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_state_get");
+ return ECORE_IMF_INPUT_PANEL_STATE_HIDE;
+ }
+
+ if (ctx->klass->input_panel_state_get)
+ state = ctx->klass->input_panel_state_get(ctx);
+
+ return state;
+}
+
+/**
+ * Register a callback function which will be called if there is change in input panel state,language,mode etc.
+ * In order to deregister the callback function
+ * Use @ref ecore_imf_context_input_panel_event_callback_del.
+ *
+ * @param ctx An #Ecore_IMF_Context
+ * @param type event type
+ * @param func the callback function
+ * @param data application-input panel specific data.
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI void
+ecore_imf_context_input_panel_event_callback_add(Ecore_IMF_Context *ctx,
+ Ecore_IMF_Input_Panel_Event type,
+ void (*func) (void *data, Ecore_IMF_Context *ctx, int value),
+ const void *data)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_event_callback_add");
+ return;
+ }
+
+ if (ctx->klass->input_panel_event_callback_add)
+ ctx->klass->input_panel_event_callback_add(ctx, type, func, (void *)data);
+}
+
+/**
+ * Unregister a callback function which will be called if there is change in input panel state, language, mode etc.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param type An #Ecore_IMF_Input_Panel_Event.
+ * @param func the callback function
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI void
+ecore_imf_context_input_panel_event_callback_del(Ecore_IMF_Context *ctx,
+ Ecore_IMF_Input_Panel_Event type,
+ void (*func) (void *data, Ecore_IMF_Context *ctx, int value))
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_event_callback_del");
+ return;
+ }
+
+ if (ctx->klass->input_panel_event_callback_del)
+ ctx->klass->input_panel_event_callback_del(ctx, type, func);
+}
+
+/**
+ * Get the current language locale of the input panel.
+ *
+ * ex) fr_FR
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param lang Location to store the retrieved language string. The
+ * string retrieved must be freed with free().
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI void
+ecore_imf_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx, char **lang)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_input_panel_language_locale_get");
+ return;
+ }
+
+ if (ctx->klass->input_panel_language_locale_get)
+ ctx->klass->input_panel_language_locale_get(ctx, lang);
+ else
+ {
+ if (lang) *lang = strdup("");
+ }
+}
+
+/**
+ * Get the geometry information of the candidate panel.
+ *
+ * @param ctx An #Ecore_IMF_Context.
+ * @param x top-left x co-ordinate of the candidate panel
+ * @param y top-left y co-ordinate of the candidate panel
+ * @param w width of the candidate panel
+ * @param h height of the candidate panel
+ * @ingroup Ecore_IMF_Context_Group
+ * @since 1.3
+ */
+EAPI void
+ecore_imf_context_candidate_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h)
+{
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_context_candidate_panel_geometry_get");
+ return;
+ }
+
+ if (ctx->klass->candidate_panel_geometry_get)
+ ctx->klass->candidate_panel_geometry_get(ctx, x, y, w, h);
+}
+
diff --git a/src/lib/ecore_imf/ecore_imf_evas.c b/src/lib/ecore_imf/ecore_imf_evas.c
new file mode 100644
index 0000000000..4a5f3dd5f4
--- /dev/null
+++ b/src/lib/ecore_imf/ecore_imf_evas.c
@@ -0,0 +1,324 @@
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Ecore.h>
+#include "ecore_private.h"
+#include "Ecore_IMF_Evas.h"
+
+/**
+ * @defgroup Ecore_IMF_Evas_Group Ecore Input Method Context Evas Helper Functions
+ *
+ * Helper functions to make it easy to use Evas with Ecore_IMF.
+ * Converts each event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * An example of usage of these functions can be found at:
+ * @li @ref ecore_imf_example_c
+ */
+
+static const char *_ecore_imf_evas_event_empty = "";
+
+/* Converts the Evas modifiers to Ecore_IMF keyboard modifiers */
+static void
+_ecore_imf_evas_event_modifiers_wrap(Evas_Modifier *evas_modifiers,
+ Ecore_IMF_Keyboard_Modifiers *imf_keyboard_modifiers)
+{
+ if (!evas_modifiers || !imf_keyboard_modifiers)
+ return;
+
+ *imf_keyboard_modifiers = ECORE_IMF_KEYBOARD_MODIFIER_NONE;
+ if (evas_key_modifier_is_set(evas_modifiers, "Control"))
+ *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
+ if (evas_key_modifier_is_set(evas_modifiers, "Alt"))
+ *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
+ if (evas_key_modifier_is_set(evas_modifiers, "Shift"))
+ *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;
+ if (evas_key_modifier_is_set(evas_modifiers, "Super") || evas_key_modifier_is_set(evas_modifiers, "Hyper"))
+ *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
+ if (evas_key_modifier_is_set(evas_modifiers, "AltGr"))
+ *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
+}
+
+/* Converts the Evas locks to Ecore_IMF keyboard locks */
+static void
+_ecore_imf_evas_event_locks_wrap(Evas_Lock *evas_locks,
+ Ecore_IMF_Keyboard_Locks *imf_keyboard_locks)
+{
+ if (!evas_locks || !imf_keyboard_locks)
+ return;
+
+ *imf_keyboard_locks = ECORE_IMF_KEYBOARD_LOCK_NONE;
+ if (evas_key_lock_is_set(evas_locks, "Num_Lock"))
+ *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_NUM;
+ if (evas_key_lock_is_set(evas_locks, "Caps_Lock"))
+ *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS;
+ if (evas_key_lock_is_set(evas_locks, "Scroll_Lock"))
+ *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL;
+}
+
+/* Converts the Evas mouse flags to Ecore_IMF mouse flags */
+static void
+_ecore_imf_evas_event_mouse_flags_wrap(Evas_Button_Flags evas_flags,
+ Ecore_IMF_Mouse_Flags *imf_flags)
+{
+ if (!imf_flags)
+ return;
+
+ *imf_flags = ECORE_IMF_MOUSE_NONE;
+ if (evas_flags & EVAS_BUTTON_DOUBLE_CLICK)
+ *imf_flags |= ECORE_IMF_MOUSE_DOUBLE_CLICK;
+ if (evas_flags & EVAS_BUTTON_TRIPLE_CLICK)
+ *imf_flags |= ECORE_IMF_MOUSE_TRIPLE_CLICK;
+}
+
+/**
+ * Converts a "mouse_in" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event,
+ Ecore_IMF_Event_Mouse_In *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->buttons = evas_event->buttons;
+ imf_event->output.x = evas_event->output.x;
+ imf_event->output.y = evas_event->output.y;
+ imf_event->canvas.x = evas_event->canvas.x;
+ imf_event->canvas.y = evas_event->canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+}
+
+/**
+ * Converts a "mouse_out" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event,
+ Ecore_IMF_Event_Mouse_Out *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->buttons = evas_event->buttons;
+ imf_event->output.x = evas_event->output.x;
+ imf_event->output.y = evas_event->output.y;
+ imf_event->canvas.x = evas_event->canvas.x;
+ imf_event->canvas.y = evas_event->canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+}
+
+/**
+ * Converts a "mouse_move" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event,
+ Ecore_IMF_Event_Mouse_Move *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->buttons = evas_event->buttons;
+ imf_event->cur.output.x = evas_event->cur.output.x;
+ imf_event->cur.output.y = evas_event->cur.output.y;
+ imf_event->prev.output.x = evas_event->prev.output.x;
+ imf_event->prev.output.y = evas_event->prev.output.y;
+ imf_event->cur.canvas.x = evas_event->cur.canvas.x;
+ imf_event->cur.canvas.y = evas_event->cur.canvas.y;
+ imf_event->prev.canvas.x = evas_event->prev.canvas.x;
+ imf_event->prev.canvas.y = evas_event->prev.canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+}
+
+/**
+ * Converts a "mouse_down" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event,
+ Ecore_IMF_Event_Mouse_Down *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->button = evas_event->button;
+ imf_event->output.x = evas_event->output.x;
+ imf_event->output.y = evas_event->output.y;
+ imf_event->canvas.x = evas_event->canvas.x;
+ imf_event->canvas.y = evas_event->canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+ _ecore_imf_evas_event_mouse_flags_wrap(evas_event->flags, &imf_event->flags);
+}
+
+/**
+ * Converts a "mouse_up" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event,
+ Ecore_IMF_Event_Mouse_Up *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->button = evas_event->button;
+ imf_event->output.x = evas_event->output.x;
+ imf_event->output.y = evas_event->output.y;
+ imf_event->canvas.x = evas_event->canvas.x;
+ imf_event->canvas.y = evas_event->canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+ _ecore_imf_evas_event_mouse_flags_wrap(evas_event->flags, &imf_event->flags);
+}
+
+/**
+ * Converts a "mouse_wheel" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ */
+EAPI void
+ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event,
+ Ecore_IMF_Event_Mouse_Wheel *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->direction = evas_event->direction;
+ imf_event->z = evas_event->z;
+ imf_event->output.x = evas_event->output.x;
+ imf_event->output.y = evas_event->output.y;
+ imf_event->canvas.x = evas_event->canvas.x;
+ imf_event->canvas.y = evas_event->canvas.y;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+ imf_event->timestamp = evas_event->timestamp;
+}
+
+/**
+ * Converts a "key_down" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+ * {
+ * Evas_Event_Key_Down *ev = event_info;
+ * if (!ev->keyname) return;
+ *
+ * if (imf_context)
+ * {
+ * Ecore_IMF_Event_Key_Down ecore_ev;
+ * ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
+ * if (ecore_imf_context_filter_event(imf_context,
+ * ECORE_IMF_EVENT_KEY_DOWN,
+ * (Ecore_IMF_Event *)&ecore_ev))
+ * return;
+ * }
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, data);
+ * @endcode
+ */
+EAPI void
+ecore_imf_evas_event_key_down_wrap(Evas_Event_Key_Down *evas_event,
+ Ecore_IMF_Event_Key_Down *imf_event)
+{
+ if (!evas_event || !imf_event)
+ return;
+
+ imf_event->keyname = evas_event->keyname ? evas_event->keyname : _ecore_imf_evas_event_empty;
+ imf_event->key = evas_event->key ? evas_event->key : _ecore_imf_evas_event_empty;
+ imf_event->string = evas_event->string ? evas_event->string : _ecore_imf_evas_event_empty;
+ imf_event->compose = evas_event->compose ? evas_event->compose : _ecore_imf_evas_event_empty;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+}
+
+/**
+ * Converts a "key_up" event from Evas to the corresponding event of Ecore_IMF.
+ *
+ * @param evas_event The received Evas event.
+ * @param imf_event The location to store the converted Ecore_IMF event.
+ * @ingroup Ecore_IMF_Evas_Group
+ *
+ * Example
+ * @code
+ * static void
+ * _key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+ * {
+ * Evas_Event_Key_Up *ev = event_info;
+ * if (!ev->keyname) return;
+ *
+ * if (imf_context)
+ * {
+ * Ecore_IMF_Event_Key_Up ecore_ev;
+ * ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev);
+ * if (ecore_imf_context_filter_event(imf_context,
+ * ECORE_IMF_EVENT_KEY_UP,
+ * (Ecore_IMF_Event *)&ecore_ev))
+ * return;
+ * }
+ * }
+ *
+ * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP, _key_up_cb, data);
+ * @endcode
+ */
+EAPI void
+ecore_imf_evas_event_key_up_wrap(Evas_Event_Key_Up *evas_event,
+ Ecore_IMF_Event_Key_Up *imf_event)
+{
+ if (!evas_event)
+ {
+ EINA_LOG_ERR("Evas event is missing");
+ return;
+ }
+
+ if (!imf_event)
+ {
+ EINA_LOG_ERR("Imf event is missing");
+ return;
+ }
+
+ imf_event->keyname = evas_event->keyname ? evas_event->keyname : _ecore_imf_evas_event_empty;
+ imf_event->key = evas_event->key ? evas_event->key : _ecore_imf_evas_event_empty;
+ imf_event->string = evas_event->string ? evas_event->string : _ecore_imf_evas_event_empty;
+ imf_event->compose = evas_event->compose ? evas_event->compose : _ecore_imf_evas_event_empty;
+ imf_event->timestamp = evas_event->timestamp;
+ _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers);
+ _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks);
+}
diff --git a/src/lib/ecore_imf/ecore_imf_module.c b/src/lib/ecore_imf/ecore_imf_module.c
new file mode 100644
index 0000000000..cbdee47178
--- /dev/null
+++ b/src/lib/ecore_imf/ecore_imf_module.c
@@ -0,0 +1,212 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <Ecore.h>
+#include <ecore_private.h>
+
+#include "Ecore_IMF.h"
+#include "ecore_imf_private.h"
+
+static void _ecore_imf_module_free(Ecore_IMF_Module *module);
+static int _ecore_imf_modules_exists(const char *ctx_id);
+
+typedef struct _Ecore_IMF_Selector
+{
+ const char *toselect;
+ void *selected;
+} Ecore_IMF_Selector;
+
+static Eina_Hash *modules = NULL;
+static Eina_Array *module_list = NULL;
+
+void
+ecore_imf_module_init(void)
+{
+ char *homedir;
+
+ module_list = eina_module_list_get(NULL, PACKAGE_LIB_DIR "/ecore/immodules", 0, NULL, NULL);
+ homedir = eina_module_environment_path_get("HOME", "/.ecore/immodules");
+ if (homedir)
+ {
+ module_list = eina_module_list_get(module_list, homedir, 0, NULL, NULL);
+ free(homedir);
+ }
+ eina_module_list_load(module_list);
+}
+
+void
+ecore_imf_module_shutdown(void)
+{
+ if (modules)
+ {
+ eina_hash_free(modules);
+ modules = NULL;
+ }
+ if (module_list)
+ {
+ eina_module_list_free(module_list);
+ eina_array_free(module_list);
+ module_list = NULL;
+ }
+}
+
+static Eina_Bool
+_hash_module_available_get(const Eina_Hash *hash EINA_UNUSED, int *data, void *list)
+{
+ *(Eina_List**)list = eina_list_append(*(Eina_List**)list, data);
+ return EINA_TRUE;
+}
+
+Eina_List *
+ecore_imf_module_available_get(void)
+{
+ Eina_List *values = NULL;
+ Eina_Iterator *it = NULL;
+
+ if (!modules) return NULL;
+
+ it = eina_hash_iterator_data_new(modules);
+ if (!it)
+ return NULL;
+
+ eina_iterator_foreach(it, EINA_EACH_CB(_hash_module_available_get), &values);
+ eina_iterator_free(it);
+
+ return values;
+}
+
+Ecore_IMF_Module *
+ecore_imf_module_get(const char *ctx_id)
+{
+ if (!modules) return NULL;
+ return eina_hash_find(modules, ctx_id);
+}
+
+Ecore_IMF_Context *
+ecore_imf_module_context_create(const char *ctx_id)
+{
+ Ecore_IMF_Module *module;
+ Ecore_IMF_Context *ctx = NULL;
+
+ if (!modules) return NULL;
+ module = eina_hash_find(modules, ctx_id);
+ if (module)
+ {
+ ctx = module->create();
+ if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+ {
+ ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+ "ecore_imf_module_context_create");
+ return NULL;
+ }
+ ctx->module = module;
+ }
+ return ctx;
+}
+
+static Eina_Bool
+_hash_ids_get(const Eina_Hash *hash EINA_UNUSED, const char *key, void *list)
+{
+ *(Eina_List**)list = eina_list_append(*(Eina_List**)list, key);
+ return EINA_TRUE;
+}
+
+Eina_List *
+ecore_imf_module_context_ids_get(void)
+{
+ Eina_List *l = NULL;
+ Eina_Iterator *it = NULL;
+
+ if (!modules) return NULL;
+
+ it = eina_hash_iterator_key_new(modules);
+ if (!it)
+ return NULL;
+
+ eina_iterator_foreach(it, EINA_EACH_CB(_hash_ids_get), &l);
+ eina_iterator_free(it);
+
+ return l;
+}
+
+static Eina_Bool
+_hash_ids_by_canvas_type_get(const Eina_Hash *hash EINA_UNUSED, void *data, void *fdata)
+{
+ Ecore_IMF_Module *module = data;
+ Ecore_IMF_Selector *selector = fdata;
+
+ if (!strcmp(module->info->canvas_type, selector->toselect))
+ selector->selected = eina_list_append(selector->selected, (void *)module->info->id);
+
+ return EINA_TRUE;
+}
+
+Eina_List *
+ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type)
+{
+ Ecore_IMF_Selector selector;
+ Eina_List *values = NULL;
+ Eina_Iterator *it = NULL;
+
+ if (!modules) return NULL;
+
+ if (!canvas_type)
+ return ecore_imf_module_context_ids_get();
+
+ it = eina_hash_iterator_data_new(modules);
+ if (!it)
+ return NULL;
+
+ selector.toselect = canvas_type;
+ selector.selected = values;
+ eina_iterator_foreach(it, EINA_EACH_CB(_hash_ids_by_canvas_type_get), &selector);
+ eina_iterator_free(it);
+
+ return values;
+}
+
+EAPI void
+ecore_imf_module_register(const Ecore_IMF_Context_Info *info,
+ Ecore_IMF_Context *(*imf_module_create)(void),
+ Ecore_IMF_Context *(*imf_module_exit)(void))
+{
+ Ecore_IMF_Module *module;
+
+ if (_ecore_imf_modules_exists(info->id)) return;
+
+ if (!modules)
+ modules = eina_hash_string_superfast_new(EINA_FREE_CB(_ecore_imf_module_free));
+
+ module = malloc(sizeof(Ecore_IMF_Module));
+ module->info = info;
+ /* cache imf_module_create as it may be used several times */
+ module->create = imf_module_create;
+ module->exit = imf_module_exit;
+
+ eina_hash_add(modules, info->id, module);
+}
+
+static void
+_ecore_imf_module_free(Ecore_IMF_Module *module)
+{
+ if (module->exit) module->exit();
+ free(module);
+}
+
+static int
+_ecore_imf_modules_exists(const char *ctx_id)
+{
+ if (!modules) return 0;
+ if (!ctx_id) return 0;
+
+ if (eina_hash_find(modules, ctx_id))
+ return 1;
+
+ return 0;
+}
diff --git a/src/lib/ecore_imf/ecore_imf_private.h b/src/lib/ecore_imf/ecore_imf_private.h
new file mode 100644
index 0000000000..b4ff0f2ee0
--- /dev/null
+++ b/src/lib/ecore_imf/ecore_imf_private.h
@@ -0,0 +1,84 @@
+#ifndef _ECORE_IMF_PRIVATE_H
+#define _ECORE_IMF_PRIVATE_H
+
+#define ECORE_MAGIC_CONTEXT 0x56c1b39a
+
+#ifdef ECORE_IMF_DEFAULT_LOG_COLOR
+#undef ECORE_IMF_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_IMF_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+extern int _ecore_imf_log_dom;
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_imf_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_imf_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_imf_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_imf_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_imf_log_dom, __VA_ARGS__)
+
+typedef struct _Ecore_IMF_Module Ecore_IMF_Module;
+typedef struct _Ecore_IMF_Func_Node Ecore_IMF_Func_Node;
+
+struct _Ecore_IMF_Context
+{
+ ECORE_MAGIC;
+ const Ecore_IMF_Module *module;
+ const Ecore_IMF_Context_Class *klass;
+ void *data;
+ int input_mode;
+ void *window;
+ void *client_canvas;
+ Eina_Bool (*retrieve_surrounding_func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
+ void *retrieve_surrounding_data;
+ Eina_List *callbacks;
+ Ecore_IMF_Autocapital_Type autocapital_type;
+ Ecore_IMF_Input_Panel_Layout input_panel_layout;
+ Ecore_IMF_Input_Panel_Lang input_panel_lang;
+ Ecore_IMF_Input_Panel_Return_Key_Type input_panel_return_key_type;
+ Eina_Bool allow_prediction : 1;
+ Eina_Bool input_panel_enabled : 1;
+ Eina_Bool input_panel_return_key_disabled : 1;
+ Eina_Bool input_panel_caps_lock_mode : 1;
+};
+
+struct _Ecore_IMF_Module
+{
+ const Ecore_IMF_Context_Info *info;
+ Ecore_IMF_Context *(*create)(void);
+ Ecore_IMF_Context *(*exit)(void);
+};
+
+struct _Ecore_IMF_Func_Node
+{
+ void (*func) ();
+ const void *data;
+ Ecore_IMF_Callback_Type type;
+};
+
+void ecore_imf_module_init(void);
+void ecore_imf_module_shutdown(void);
+Eina_List *ecore_imf_module_available_get(void);
+Ecore_IMF_Module *ecore_imf_module_get(const char *ctx_id);
+Ecore_IMF_Context *ecore_imf_module_context_create(const char *ctx_id);
+Eina_List *ecore_imf_module_context_ids_get(void);
+Eina_List *ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type);
+
+#endif
diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h
new file mode 100644
index 0000000000..d1feb220e1
--- /dev/null
+++ b/src/lib/ecore_input/Ecore_Input.h
@@ -0,0 +1,236 @@
+#ifndef _ECORE_INPUT_H
+#define _ECORE_INPUT_H
+
+#ifdef _WIN32
+# include <stddef.h>
+#else
+# include <inttypes.h>
+#endif
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_INPUT_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_INPUT_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ EAPI extern int ECORE_EVENT_KEY_DOWN;
+ EAPI extern int ECORE_EVENT_KEY_UP;
+ EAPI extern int ECORE_EVENT_MOUSE_BUTTON_DOWN;
+ EAPI extern int ECORE_EVENT_MOUSE_BUTTON_UP;
+ EAPI extern int ECORE_EVENT_MOUSE_MOVE;
+ EAPI extern int ECORE_EVENT_MOUSE_WHEEL;
+ EAPI extern int ECORE_EVENT_MOUSE_IN;
+ EAPI extern int ECORE_EVENT_MOUSE_OUT;
+
+#define ECORE_EVENT_MODIFIER_SHIFT 0x0001
+#define ECORE_EVENT_MODIFIER_CTRL 0x0002
+#define ECORE_EVENT_MODIFIER_ALT 0x0004
+#define ECORE_EVENT_MODIFIER_WIN 0x0008
+#define ECORE_EVENT_MODIFIER_SCROLL 0x0010
+#define ECORE_EVENT_MODIFIER_NUM 0x0020
+#define ECORE_EVENT_MODIFIER_CAPS 0x0040
+#define ECORE_EVENT_LOCK_SCROLL 0x0080
+#define ECORE_EVENT_LOCK_NUM 0x0100
+#define ECORE_EVENT_LOCK_CAPS 0x0200
+#define ECORE_EVENT_LOCK_SHIFT 0x0300
+#define ECORE_EVENT_MODIFIER_ALTGR 0x0400 /**< @since 1.7 */
+
+ typedef uintptr_t Ecore_Window;
+ typedef struct _Ecore_Event_Key Ecore_Event_Key;
+ typedef struct _Ecore_Event_Mouse_Button Ecore_Event_Mouse_Button;
+ typedef struct _Ecore_Event_Mouse_Wheel Ecore_Event_Mouse_Wheel;
+ typedef struct _Ecore_Event_Mouse_Move Ecore_Event_Mouse_Move;
+ typedef struct _Ecore_Event_Mouse_IO Ecore_Event_Mouse_IO;
+ typedef struct _Ecore_Event_Modifiers Ecore_Event_Modifiers;
+
+ typedef enum _Ecore_Event_Modifier
+ {
+ ECORE_NONE,
+ ECORE_SHIFT,
+ ECORE_CTRL,
+ ECORE_ALT,
+ ECORE_WIN,
+ ECORE_SCROLL,
+ ECORE_CAPS,
+ ECORE_MODE, /**< @since 1.7 */
+ ECORE_LAST
+ } Ecore_Event_Modifier;
+
+ typedef enum _Ecore_Event_Press
+ {
+ ECORE_DOWN,
+ ECORE_UP
+ } Ecore_Event_Press;
+
+ typedef enum _Ecore_Event_IO
+ {
+ ECORE_IN,
+ ECORE_OUT
+ } Ecore_Event_IO;
+
+ typedef enum _Ecore_Compose_State
+ {
+ ECORE_COMPOSE_NONE,
+ ECORE_COMPOSE_MIDDLE,
+ ECORE_COMPOSE_DONE
+ } Ecore_Compose_State;
+
+ struct _Ecore_Event_Key
+ {
+ const char *keyname;
+ const char *key;
+ const char *string;
+ const char *compose;
+ Ecore_Window window;
+ Ecore_Window root_window;
+ Ecore_Window event_window;
+
+ unsigned int timestamp;
+ unsigned int modifiers;
+
+ int same_screen;
+ };
+
+ struct _Ecore_Event_Mouse_Button
+ {
+ Ecore_Window window;
+ Ecore_Window root_window;
+ Ecore_Window event_window;
+
+ unsigned int timestamp;
+ unsigned int modifiers;
+ unsigned int buttons;
+ unsigned int double_click;
+ unsigned int triple_click;
+ int same_screen;
+
+ int x;
+ int y;
+ struct {
+ int x;
+ int y;
+ } root;
+
+ struct {
+ int device; /* 0 if normal mouse, 1+ for other mouse-devices (eg multi-touch - other fingers) */
+ double radius, radius_x, radius_y; /* radius of press point - radius_x and y if its an ellipse (radius is the average of the 2) */
+ double pressure; /* pressure - 1.0 == normal, > 1.0 == more, 0.0 == none */
+ double angle; /* angle relative to perpendicular (0.0 == perpendicular), in degrees */
+ double x, y; /* same as x, y root.x, root.y, but with sub-pixel precision, if available */
+ struct {
+ double x, y;
+ } root;
+ } multi;
+ };
+
+ struct _Ecore_Event_Mouse_Wheel
+ {
+ Ecore_Window window;
+ Ecore_Window root_window;
+ Ecore_Window event_window;
+
+ unsigned int timestamp;
+ unsigned int modifiers;
+
+ int same_screen;
+ int direction;
+ int z;
+
+ int x;
+ int y;
+ struct {
+ int x;
+ int y;
+ } root;
+ };
+
+ struct _Ecore_Event_Mouse_Move
+ {
+ Ecore_Window window;
+ Ecore_Window root_window;
+ Ecore_Window event_window;
+
+ unsigned int timestamp;
+ unsigned int modifiers;
+
+ int same_screen;
+
+ int x;
+ int y;
+ struct {
+ int x;
+ int y;
+ } root;
+
+ struct {
+ int device; /* 0 if normal mouse, 1+ for other mouse-devices (eg multi-touch - other fingers) */
+ double radius, radius_x, radius_y; /* radius of press point - radius_x and y if its an ellipse (radius is the average of the 2) */
+ double pressure; /* pressure - 1.0 == normal, > 1.0 == more, 0.0 == none */
+ double angle; /* angle relative to perpendicular (0.0 == perpendicular), in degrees */
+ double x, y; /* same as x, y root.x, root.y, but with sub-pixel precision, if available */
+ struct {
+ double x, y;
+ } root;
+ } multi;
+ };
+
+ struct _Ecore_Event_Mouse_IO
+ {
+ Ecore_Window window;
+ Ecore_Window event_window;
+
+ unsigned int timestamp;
+ unsigned int modifiers;
+
+ int x;
+ int y;
+ };
+
+ struct _Ecore_Event_Modifiers
+ {
+ unsigned int size;
+ unsigned int array[ECORE_LAST];
+ };
+
+ EAPI int ecore_event_init(void);
+ EAPI int ecore_event_shutdown(void);
+
+ EAPI unsigned int ecore_event_modifier_mask(Ecore_Event_Modifier modifier);
+ EAPI Ecore_Event_Modifier ecore_event_update_modifier(const char *key, Ecore_Event_Modifiers *modifiers, int inc);
+
+ /**
+ * @since 1.7
+ */
+ EAPI Ecore_Compose_State ecore_compose_get(const Eina_List *seq, char **seqstr_ret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_input/Ecore_Input_Evas.h b/src/lib/ecore_input/Ecore_Input_Evas.h
new file mode 100644
index 0000000000..c97274eb0b
--- /dev/null
+++ b/src/lib/ecore_input/Ecore_Input_Evas.h
@@ -0,0 +1,64 @@
+#ifndef _ECORE_INPUT_EVAS_H
+#define _ECORE_INPUT_EVAS_H
+
+#include <Evas.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_INPUT_EVAS_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_INPUT_EVAS_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*Ecore_Event_Mouse_Move_Cb)(void *window, int x, int y, unsigned int timestamp);
+typedef void (*Ecore_Event_Multi_Move_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, unsigned int timestamp);
+typedef void (*Ecore_Event_Multi_Down_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, Evas_Button_Flags flags, unsigned int timestamp);
+typedef void (*Ecore_Event_Multi_Up_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, Evas_Button_Flags flags, unsigned int timestamp);
+
+EAPI int ecore_event_evas_init(void);
+EAPI int ecore_event_evas_shutdown(void);
+
+EAPI Eina_Bool ecore_event_evas_key_down(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_key_up(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_button_up(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_button_down(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_wheel(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_move(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_in(void *data, int type, void *event);
+EAPI Eina_Bool ecore_event_evas_mouse_out(void *data, int type, void *event);
+
+EAPI void ecore_event_window_register(Ecore_Window id, void *window, Evas *evas, Ecore_Event_Mouse_Move_Cb move_mouse, Ecore_Event_Multi_Move_Cb move_multi, Ecore_Event_Multi_Down_Cb down_multi, Ecore_Event_Multi_Up_Cb up_multi);
+EAPI void ecore_event_window_unregister(Ecore_Window id);
+EAPI void *ecore_event_window_match(Ecore_Window id);
+EAPI void ecore_event_window_ignore_events(Ecore_Window id, int ignore_event);
+
+EAPI void ecore_event_evas_modifier_lock_update(Evas *e, unsigned int modifiers);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_input/ecore_input.c b/src/lib/ecore_input/ecore_input.c
new file mode 100644
index 0000000000..8f4b1f9bc0
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input.c
@@ -0,0 +1,127 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#include "Ecore_Input.h"
+#include "ecore_input_private.h"
+
+
+int _ecore_input_log_dom = -1;
+
+EAPI int ECORE_EVENT_KEY_DOWN = 0;
+EAPI int ECORE_EVENT_KEY_UP = 0;
+EAPI int ECORE_EVENT_MOUSE_BUTTON_DOWN = 0;
+EAPI int ECORE_EVENT_MOUSE_BUTTON_UP = 0;
+EAPI int ECORE_EVENT_MOUSE_MOVE = 0;
+EAPI int ECORE_EVENT_MOUSE_WHEEL = 0;
+EAPI int ECORE_EVENT_MOUSE_IN = 0;
+EAPI int ECORE_EVENT_MOUSE_OUT = 0;
+
+static int _ecore_event_init_count = 0;
+
+EAPI int
+ecore_event_init(void)
+{
+ if (++_ecore_event_init_count != 1)
+ return _ecore_event_init_count;
+ if (!ecore_init())
+ {
+ _ecore_event_init_count--;
+ return 0;
+ }
+
+ _ecore_input_log_dom = eina_log_domain_register
+ ("ecore_input", ECORE_INPUT_DEFAULT_LOG_COLOR);
+ if(_ecore_input_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the ecore input module.");
+ return --_ecore_event_init_count;
+ }
+
+ ECORE_EVENT_KEY_DOWN = ecore_event_type_new();
+ ECORE_EVENT_KEY_UP = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_MOVE = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_WHEEL = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_EVENT_MOUSE_OUT = ecore_event_type_new();
+
+ return _ecore_event_init_count;
+}
+
+EAPI int
+ecore_event_shutdown(void)
+{
+ if (--_ecore_event_init_count != 0)
+ return _ecore_event_init_count;
+
+ ECORE_EVENT_KEY_DOWN = 0;
+ ECORE_EVENT_KEY_UP = 0;
+ ECORE_EVENT_MOUSE_BUTTON_DOWN = 0;
+ ECORE_EVENT_MOUSE_BUTTON_UP = 0;
+ ECORE_EVENT_MOUSE_MOVE = 0;
+ ECORE_EVENT_MOUSE_WHEEL = 0;
+ ECORE_EVENT_MOUSE_IN = 0;
+ ECORE_EVENT_MOUSE_OUT = 0;
+ eina_log_domain_unregister(_ecore_input_log_dom);
+ _ecore_input_log_dom = -1;
+ ecore_shutdown();
+ return _ecore_event_init_count;
+}
+
+typedef struct _Ecore_Event_Modifier_Match Ecore_Event_Modifier_Match;
+struct _Ecore_Event_Modifier_Match
+{
+ const char *key;
+ Ecore_Event_Modifier modifier;
+ unsigned int event_modifier;
+};
+
+static const Ecore_Event_Modifier_Match matchs[] = {
+ { "Shift_L", ECORE_SHIFT, ECORE_EVENT_MODIFIER_SHIFT },
+ { "Shift_R", ECORE_SHIFT, ECORE_EVENT_MODIFIER_SHIFT },
+ { "Alt_L", ECORE_ALT, ECORE_EVENT_MODIFIER_ALT },
+ { "Alt_R", ECORE_ALT, ECORE_EVENT_MODIFIER_ALT },
+ { "Control_L", ECORE_CTRL, ECORE_EVENT_MODIFIER_CTRL },
+ { "Control_R", ECORE_CTRL, ECORE_EVENT_MODIFIER_CTRL },
+ { "Caps_Lock", ECORE_CAPS, ECORE_EVENT_MODIFIER_CAPS },
+ { "Super_L", ECORE_WIN, ECORE_EVENT_MODIFIER_WIN },
+ { "Super_R", ECORE_WIN, ECORE_EVENT_MODIFIER_WIN },
+ { "ISO_Level3_Shift", ECORE_MODE, ECORE_EVENT_MODIFIER_ALTGR },
+ { "Scroll_Lock", ECORE_SCROLL, ECORE_EVENT_MODIFIER_SCROLL }
+};
+
+EAPI unsigned int
+ecore_event_modifier_mask(Ecore_Event_Modifier modifier)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof (matchs) / sizeof (Ecore_Event_Modifier_Match); i++)
+ if (matchs[i].modifier == modifier)
+ return matchs[i].event_modifier;
+
+ return 0;
+}
+
+EAPI Ecore_Event_Modifier
+ecore_event_update_modifier(const char *key, Ecore_Event_Modifiers *modifiers, int inc)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof (matchs) / sizeof (Ecore_Event_Modifier_Match); i++)
+ if (strcmp(matchs[i].key, key) == 0)
+ {
+ if (modifiers && matchs[i].modifier < modifiers->size)
+ modifiers->array[matchs[i].modifier] += inc;
+ return matchs[i].modifier;
+ }
+
+ return ECORE_NONE;
+}
diff --git a/src/lib/ecore_input/ecore_input_compose.c b/src/lib/ecore_input/ecore_input_compose.c
new file mode 100644
index 0000000000..5335a7fe0c
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input_compose.c
@@ -0,0 +1,61 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#include "Ecore_Input.h"
+#include "ecore_input_private.h"
+
+// some info on a big big big compose table
+// http://cgit.freedesktop.org/xorg/lib/libX11/plain/nls/en_US.UTF-8/Compose.pre
+// isolate compose tree into its own file - hand crafted into static const c
+#include "ecore_input_compose.h"
+
+EAPI Ecore_Compose_State
+ecore_compose_get(const Eina_List *seq, char **seqstr_ret)
+{
+ Comp *c, *cend;
+ Eina_List *l;
+ const char *s;
+ int i = 0;
+
+ if (!seq) return ECORE_COMPOSE_NONE;
+ l = (Eina_List *)seq;
+ s = l->data;
+ cend = (Comp *)comp + (sizeof(comp) / sizeof(comp[0]));
+ for (c = (Comp *)comp; c->s && s;)
+ {
+ // doesn't match -> jump to next level entry
+ if (!(!strcmp(s, c->s)))
+ {
+ c += c->jump + 1;
+ if (c >= cend)
+ {
+ return ECORE_COMPOSE_NONE;
+ }
+ }
+ else
+ {
+ cend = c + c->jump;
+ // advance to next sequence member
+ l = l->next;
+ i++;
+ if (l) s = l->data;
+ else s = NULL;
+ c++;
+ // if advanced item jump is an endpoint - it's the string we want
+ if (c->jump == 0)
+ {
+ if (seqstr_ret) *seqstr_ret = strdup(c->s);
+ return ECORE_COMPOSE_DONE;
+ }
+ }
+ }
+ if (i == 0) return ECORE_COMPOSE_NONE;
+ return ECORE_COMPOSE_MIDDLE;
+}
diff --git a/src/lib/ecore_input/ecore_input_compose.h b/src/lib/ecore_input/ecore_input_compose.h
new file mode 100644
index 0000000000..9fbfb76616
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input_compose.h
@@ -0,0 +1,9895 @@
+typedef struct _Comp Comp;
+struct _Comp {
+ const char *s;
+ int jump;
+};
+
+static const Comp comp[] = {
+ {"dead_breve", 124},
+ {"dead_breve", 1},
+ {"˘", 0},
+ {"g", 1},
+ {"ğ", 0},
+ {"a", 1},
+ {"ă", 0},
+ {"Greek_IOTA", 1},
+ {"Ῐ", 0},
+ {"dead_grave", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"Greek_iota", 1},
+ {"ῐ", 0},
+ {"e", 1},
+ {"ĕ", 0},
+ {"agrave", 1},
+ {"ằ", 0},
+ {"o", 1},
+ {"ŏ", 0},
+ {"Greek_upsilon", 1},
+ {"ῠ", 0},
+ {"ahook", 1},
+ {"ẳ", 0},
+ {"dead_belowdot", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"space", 1},
+ {"˘", 0},
+ {"Cyrillic_I", 1},
+ {"Й", 0},
+ {"Multi_key", 15},
+ {"exclam", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"comma", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"i", 1},
+ {"ĭ", 0},
+ {"dead_tilde", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"Cyrillic_a", 1},
+ {"ӑ", 0},
+ {"Cyrillic_U", 1},
+ {"Ў", 0},
+ {"nobreakspace", 1},
+ {"̆", 0},
+ {"u", 1},
+ {"ŭ", 0},
+ {"G", 1},
+ {"Ğ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾰ", 0},
+ {"atilde", 1},
+ {"ẵ", 0},
+ {"Cyrillic_ie", 1},
+ {"ӗ", 0},
+ {"E", 1},
+ {"Ĕ", 0},
+ {"Cyrillic_i", 1},
+ {"й", 0},
+ {"Atilde", 1},
+ {"Ẵ", 0},
+ {"Cyrillic_zhe", 1},
+ {"ӂ", 0},
+ {"Greek_alpha", 1},
+ {"ᾰ", 0},
+ {"Ahook", 1},
+ {"Ẳ", 0},
+ {"O", 1},
+ {"Ŏ", 0},
+ {"A", 1},
+ {"Ă", 0},
+ {"Cyrillic_A", 1},
+ {"Ӑ", 0},
+ {"dead_hook", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"Cyrillic_ZHE", 1},
+ {"Ӂ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ӗ", 0},
+ {"Aacute", 1},
+ {"Ắ", 0},
+ {"dead_cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"aacute", 1},
+ {"ắ", 0},
+ {"dead_acute", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"Agrave", 1},
+ {"Ằ", 0},
+ {"I", 1},
+ {"Ĭ", 0},
+ {"U", 1},
+ {"Ŭ", 0},
+ {"Cyrillic_u", 1},
+ {"ў", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῠ", 0},
+ {"dead_grave", 351},
+ {"W", 1},
+ {"Ẁ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"a", 1},
+ {"à", 0},
+ {"Greek_IOTA", 1},
+ {"Ὶ", 0},
+ {"dead_grave", 1},
+ {"`", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ờ", 0},
+ {"u", 1},
+ {"ừ", 0},
+ {"O", 1},
+ {"Ờ", 0},
+ {"U", 1},
+ {"Ừ", 0},
+ {"Greek_iota", 1},
+ {"ὶ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ầ", 0},
+ {"e", 1},
+ {"ề", 0},
+ {"o", 1},
+ {"ồ", 0},
+ {"E", 1},
+ {"Ề", 0},
+ {"O", 1},
+ {"Ồ", 0},
+ {"A", 1},
+ {"Ầ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὸ", 0},
+ {"Acircumflex", 1},
+ {"Ầ", 0},
+ {"Cyrillic_er", 1},
+ {"р̀", 0},
+ {"e", 1},
+ {"è", 0},
+ {"o", 1},
+ {"ò", 0},
+ {"Udiaeresis", 1},
+ {"Ǜ", 0},
+ {"Greek_upsilon", 1},
+ {"ὺ", 0},
+ {"uhorn", 1},
+ {"ừ", 0},
+ {"space", 1},
+ {"`", 0},
+ {"dead_macron", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"acircumflex", 1},
+ {"ầ", 0},
+ {"Ecircumflex", 1},
+ {"Ề", 0},
+ {"Cyrillic_I", 1},
+ {"Ѝ", 0},
+ {"y", 1},
+ {"ỳ", 0},
+ {"Multi_key", 115},
+ {"b", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"parenright", 26},
+ {"Greek_IOTA", 1},
+ {"Ἲ", 0},
+ {"Greek_iota", 1},
+ {"ἲ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὂ", 0},
+ {"Greek_upsilon", 1},
+ {"ὒ", 0},
+ {"Greek_epsilon", 1},
+ {"ἒ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἂ", 0},
+ {"Greek_omicron", 1},
+ {"ὂ", 0},
+ {"Greek_eta", 1},
+ {"ἢ", 0},
+ {"Greek_alpha", 1},
+ {"ἂ", 0},
+ {"Greek_ETA", 1},
+ {"Ἢ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἒ", 0},
+ {"Greek_omega", 1},
+ {"ὢ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὢ", 0},
+ {"quotedbl", 8},
+ {"Greek_iota", 1},
+ {"ῒ", 0},
+ {"Greek_upsilon", 1},
+ {"ῢ", 0},
+ {"u", 1},
+ {"ǜ", 0},
+ {"U", 1},
+ {"Ǜ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ờ", 0},
+ {"u", 1},
+ {"ừ", 0},
+ {"O", 1},
+ {"Ờ", 0},
+ {"U", 1},
+ {"Ừ", 0},
+ {"underscore", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"macron", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"parenleft", 28},
+ {"Greek_IOTA", 1},
+ {"Ἳ", 0},
+ {"Greek_iota", 1},
+ {"ἳ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὃ", 0},
+ {"Greek_upsilon", 1},
+ {"ὓ", 0},
+ {"Greek_epsilon", 1},
+ {"ἓ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἃ", 0},
+ {"Greek_omicron", 1},
+ {"ὃ", 0},
+ {"Greek_eta", 1},
+ {"ἣ", 0},
+ {"Greek_alpha", 1},
+ {"ἃ", 0},
+ {"Greek_ETA", 1},
+ {"Ἣ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἓ", 0},
+ {"Greek_omega", 1},
+ {"ὣ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὓ", 0},
+ {"U", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ầ", 0},
+ {"e", 1},
+ {"ề", 0},
+ {"o", 1},
+ {"ồ", 0},
+ {"E", 1},
+ {"Ề", 0},
+ {"O", 1},
+ {"Ồ", 0},
+ {"A", 1},
+ {"Ầ", 0},
+ {"Cyrillic_O", 1},
+ {"О̀", 0},
+ {"i", 1},
+ {"ì", 0},
+ {"n", 1},
+ {"ǹ", 0},
+ {"Cyrillic_a", 1},
+ {"а̀", 0},
+ {"Ohorn", 1},
+ {"Ờ", 0},
+ {"ohorn", 1},
+ {"ờ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̀", 0},
+ {"Greek_epsilon", 1},
+ {"ὲ", 0},
+ {"Cyrillic_U", 1},
+ {"У̀", 0},
+ {"nobreakspace", 1},
+ {"̀", 0},
+ {"V", 1},
+ {"Ǜ", 0},
+ {"Ocircumflex", 1},
+ {"Ồ", 0},
+ {"omacron", 1},
+ {"ṑ", 0},
+ {"ocircumflex", 1},
+ {"ồ", 0},
+ {"u", 1},
+ {"ù", 0},
+ {"Greek_ALPHA", 1},
+ {"Ὰ", 0},
+ {"Cyrillic_ie", 1},
+ {"ѐ", 0},
+ {"emacron", 1},
+ {"ḕ", 0},
+ {"E", 1},
+ {"È", 0},
+ {"Greek_iotadieresis", 1},
+ {"ῒ", 0},
+ {"Y", 1},
+ {"Ỳ", 0},
+ {"Cyrillic_i", 1},
+ {"ѝ", 0},
+ {"dead_dasia", 28},
+ {"Greek_IOTA", 1},
+ {"Ἳ", 0},
+ {"Greek_iota", 1},
+ {"ἳ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὃ", 0},
+ {"Greek_upsilon", 1},
+ {"ὓ", 0},
+ {"Greek_epsilon", 1},
+ {"ἓ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἃ", 0},
+ {"Greek_omicron", 1},
+ {"ὃ", 0},
+ {"Greek_eta", 1},
+ {"ἣ", 0},
+ {"Greek_alpha", 1},
+ {"ἃ", 0},
+ {"Greek_ETA", 1},
+ {"Ἣ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἓ", 0},
+ {"Greek_omega", 1},
+ {"ὣ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὓ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ῢ", 0},
+ {"Greek_omicron", 1},
+ {"ὸ", 0},
+ {"Greek_eta", 1},
+ {"ὴ", 0},
+ {"Abreve", 1},
+ {"Ằ", 0},
+ {"dead_psili", 26},
+ {"Greek_IOTA", 1},
+ {"Ἲ", 0},
+ {"Greek_iota", 1},
+ {"ἲ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὂ", 0},
+ {"Greek_upsilon", 1},
+ {"ὒ", 0},
+ {"Greek_epsilon", 1},
+ {"ἒ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἂ", 0},
+ {"Greek_omicron", 1},
+ {"ὂ", 0},
+ {"Greek_eta", 1},
+ {"ἢ", 0},
+ {"Greek_alpha", 1},
+ {"ἂ", 0},
+ {"Greek_ETA", 1},
+ {"Ἢ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἒ", 0},
+ {"Greek_omega", 1},
+ {"ὢ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὢ", 0},
+ {"Greek_alpha", 1},
+ {"ὰ", 0},
+ {"ecircumflex", 1},
+ {"ề", 0},
+ {"w", 1},
+ {"ẁ", 0},
+ {"Greek_ETA", 1},
+ {"Ὴ", 0},
+ {"Cyrillic_o", 1},
+ {"о̀", 0},
+ {"Emacron", 1},
+ {"Ḕ", 0},
+ {"v", 1},
+ {"ǜ", 0},
+ {"O", 1},
+ {"Ò", 0},
+ {"abreve", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"À", 0},
+ {"Greek_EPSILON", 1},
+ {"Ὲ", 0},
+ {"Cyrillic_A", 1},
+ {"А̀", 0},
+ {"Omacron", 1},
+ {"Ṑ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ѐ", 0},
+ {"Greek_omega", 1},
+ {"ὼ", 0},
+ {"dead_diaeresis", 8},
+ {"Greek_iota", 1},
+ {"ῒ", 0},
+ {"Greek_upsilon", 1},
+ {"ῢ", 0},
+ {"u", 1},
+ {"ǜ", 0},
+ {"U", 1},
+ {"Ǜ", 0},
+ {"Uhorn", 1},
+ {"Ừ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὼ", 0},
+ {"udiaeresis", 1},
+ {"ǜ", 0},
+ {"I", 1},
+ {"Ì", 0},
+ {"N", 1},
+ {"Ǹ", 0},
+ {"U", 1},
+ {"Ù", 0},
+ {"Cyrillic_u", 1},
+ {"у̀", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὺ", 0},
+ {"dead_horn", 99},
+ {"Uhook", 1},
+ {"Ử", 0},
+ {"Obelowdot", 1},
+ {"Ợ", 0},
+ {"Ograve", 1},
+ {"Ờ", 0},
+ {"dead_grave", 8},
+ {"o", 1},
+ {"ờ", 0},
+ {"u", 1},
+ {"ừ", 0},
+ {"O", 1},
+ {"Ờ", 0},
+ {"U", 1},
+ {"Ừ", 0},
+ {"dead_horn", 1},
+ {"̛", 0},
+ {"Oacute", 1},
+ {"Ớ", 0},
+ {"ohook", 1},
+ {"ở", 0},
+ {"o", 1},
+ {"ơ", 0},
+ {"Utilde", 1},
+ {"Ữ", 0},
+ {"dead_belowdot", 8},
+ {"o", 1},
+ {"ợ", 0},
+ {"u", 1},
+ {"ự", 0},
+ {"O", 1},
+ {"Ợ", 0},
+ {"U", 1},
+ {"Ự", 0},
+ {"space", 1},
+ {"̛", 0},
+ {"ubelowdot", 1},
+ {"ự", 0},
+ {"oacute", 1},
+ {"ớ", 0},
+ {"uhook", 1},
+ {"ử", 0},
+ {"dead_tilde", 8},
+ {"o", 1},
+ {"ỡ", 0},
+ {"u", 1},
+ {"ữ", 0},
+ {"O", 1},
+ {"Ỡ", 0},
+ {"U", 1},
+ {"Ữ", 0},
+ {"Uacute", 1},
+ {"Ứ", 0},
+ {"Ugrave", 1},
+ {"Ừ", 0},
+ {"nobreakspace", 1},
+ {"̛", 0},
+ {"uacute", 1},
+ {"ứ", 0},
+ {"u", 1},
+ {"ư", 0},
+ {"otilde", 1},
+ {"ỡ", 0},
+ {"utilde", 1},
+ {"ữ", 0},
+ {"Otilde", 1},
+ {"Ỡ", 0},
+ {"ograve", 1},
+ {"ờ", 0},
+ {"Ohook", 1},
+ {"Ở", 0},
+ {"O", 1},
+ {"Ơ", 0},
+ {"Ubelowdot", 1},
+ {"Ự", 0},
+ {"dead_hook", 8},
+ {"o", 1},
+ {"ở", 0},
+ {"u", 1},
+ {"ử", 0},
+ {"O", 1},
+ {"Ở", 0},
+ {"U", 1},
+ {"Ử", 0},
+ {"ugrave", 1},
+ {"ừ", 0},
+ {"obelowdot", 1},
+ {"ợ", 0},
+ {"dead_acute", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"U", 1},
+ {"Ư", 0},
+ {"dead_circumflex", 335},
+ {"minus", 1},
+ {"⁻", 0},
+ {"W", 1},
+ {"Ŵ", 0},
+ {"g", 1},
+ {"ĝ", 0},
+ {"a", 1},
+ {"â", 0},
+ {"Ograve", 1},
+ {"Ồ", 0},
+ {"dead_circumflex", 1},
+ {"^", 0},
+ {"dead_grave", 12},
+ {"a", 1},
+ {"ầ", 0},
+ {"e", 1},
+ {"ề", 0},
+ {"o", 1},
+ {"ồ", 0},
+ {"E", 1},
+ {"Ề", 0},
+ {"O", 1},
+ {"Ồ", 0},
+ {"A", 1},
+ {"Ầ", 0},
+ {"Ehook", 1},
+ {"Ể", 0},
+ {"1", 1},
+ {"¹", 0},
+ {"C", 1},
+ {"Ĉ", 0},
+ {"KP_4", 1},
+ {"⁴", 0},
+ {"Oacute", 1},
+ {"Ố", 0},
+ {"Cyrillic_er", 1},
+ {"р̂", 0},
+ {"ohook", 1},
+ {"ổ", 0},
+ {"e", 1},
+ {"ê", 0},
+ {"agrave", 1},
+ {"ầ", 0},
+ {"KP_6", 1},
+ {"⁶", 0},
+ {"o", 1},
+ {"ô", 0},
+ {"ahook", 1},
+ {"ẩ", 0},
+ {"dead_belowdot", 12},
+ {"a", 1},
+ {"ậ", 0},
+ {"e", 1},
+ {"ệ", 0},
+ {"o", 1},
+ {"ộ", 0},
+ {"E", 1},
+ {"Ệ", 0},
+ {"O", 1},
+ {"Ộ", 0},
+ {"A", 1},
+ {"Ậ", 0},
+ {"space", 1},
+ {"^", 0},
+ {"KP_8", 1},
+ {"⁸", 0},
+ {"Etilde", 1},
+ {"Ễ", 0},
+ {"Cyrillic_I", 1},
+ {"И̂", 0},
+ {"y", 1},
+ {"ŷ", 0},
+ {"Multi_key", 83},
+ {"exclam", 12},
+ {"a", 1},
+ {"ậ", 0},
+ {"e", 1},
+ {"ệ", 0},
+ {"o", 1},
+ {"ộ", 0},
+ {"E", 1},
+ {"Ệ", 0},
+ {"O", 1},
+ {"Ộ", 0},
+ {"A", 1},
+ {"Ậ", 0},
+ {"t", 4},
+ {"M", 1},
+ {"™", 0},
+ {"m", 1},
+ {"™", 0},
+ {"underbar", 24},
+ {"a", 1},
+ {"ª", 0},
+ {"o", 1},
+ {"º", 0},
+ {"l", 1},
+ {"ˡ", 0},
+ {"y", 1},
+ {"ʸ", 0},
+ {"i", 1},
+ {"ⁱ", 0},
+ {"n", 1},
+ {"ⁿ", 0},
+ {"j", 1},
+ {"ʲ", 0},
+ {"x", 1},
+ {"ˣ", 0},
+ {"w", 1},
+ {"ʷ", 0},
+ {"r", 1},
+ {"ʳ", 0},
+ {"s", 1},
+ {"ˢ", 0},
+ {"h", 1},
+ {"ʰ", 0},
+ {"S", 4},
+ {"M", 1},
+ {"℠", 0},
+ {"m", 1},
+ {"℠", 0},
+ {"underscore", 24},
+ {"a", 1},
+ {"ª", 0},
+ {"o", 1},
+ {"º", 0},
+ {"l", 1},
+ {"ˡ", 0},
+ {"y", 1},
+ {"ʸ", 0},
+ {"i", 1},
+ {"ⁱ", 0},
+ {"n", 1},
+ {"ⁿ", 0},
+ {"j", 1},
+ {"ʲ", 0},
+ {"x", 1},
+ {"ˣ", 0},
+ {"w", 1},
+ {"ʷ", 0},
+ {"r", 1},
+ {"ʳ", 0},
+ {"s", 1},
+ {"ˢ", 0},
+ {"h", 1},
+ {"ʰ", 0},
+ {"s", 4},
+ {"M", 1},
+ {"℠", 0},
+ {"m", 1},
+ {"℠", 0},
+ {"T", 4},
+ {"M", 1},
+ {"™", 0},
+ {"m", 1},
+ {"™", 0},
+ {"oacute", 1},
+ {"ố", 0},
+ {"Cyrillic_O", 1},
+ {"О̂", 0},
+ {"i", 1},
+ {"î", 0},
+ {"KP_9", 1},
+ {"⁹", 0},
+ {"equal", 1},
+ {"⁼", 0},
+ {"KP_Space", 1},
+ {"²", 0},
+ {"dead_tilde", 12},
+ {"a", 1},
+ {"ẫ", 0},
+ {"e", 1},
+ {"ễ", 0},
+ {"o", 1},
+ {"ỗ", 0},
+ {"E", 1},
+ {"Ễ", 0},
+ {"O", 1},
+ {"Ỗ", 0},
+ {"A", 1},
+ {"Ẫ", 0},
+ {"7", 1},
+ {"⁷", 0},
+ {"Cyrillic_a", 1},
+ {"а̂", 0},
+ {"j", 1},
+ {"ĵ", 0},
+ {"parenright", 1},
+ {"⁾", 0},
+ {"Eacute", 1},
+ {"Ế", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̂", 0},
+ {"KP_7", 1},
+ {"⁷", 0},
+ {"Cyrillic_U", 1},
+ {"У̂", 0},
+ {"nobreakspace", 1},
+ {"̂", 0},
+ {"u", 1},
+ {"û", 0},
+ {"z", 1},
+ {"ẑ", 0},
+ {"G", 1},
+ {"Ĝ", 0},
+ {"otilde", 1},
+ {"ỗ", 0},
+ {"H", 1},
+ {"Ĥ", 0},
+ {"8", 1},
+ {"⁸", 0},
+ {"KP_1", 1},
+ {"¹", 0},
+ {"atilde", 1},
+ {"ẫ", 0},
+ {"3", 1},
+ {"³", 0},
+ {"Cyrillic_ie", 1},
+ {"е̂", 0},
+ {"E", 1},
+ {"Ê", 0},
+ {"S", 1},
+ {"Ŝ", 0},
+ {"2", 1},
+ {"²", 0},
+ {"Y", 1},
+ {"Ŷ", 0},
+ {"Cyrillic_i", 1},
+ {"и̂", 0},
+ {"Otilde", 1},
+ {"Ỗ", 0},
+ {"Atilde", 1},
+ {"Ẫ", 0},
+ {"egrave", 1},
+ {"ề", 0},
+ {"ograve", 1},
+ {"ồ", 0},
+ {"plus", 1},
+ {"⁺", 0},
+ {"6", 1},
+ {"⁶", 0},
+ {"Ahook", 1},
+ {"Ẩ", 0},
+ {"w", 1},
+ {"ŵ", 0},
+ {"Ohook", 1},
+ {"Ổ", 0},
+ {"Cyrillic_o", 1},
+ {"о̂", 0},
+ {"4", 1},
+ {"⁴", 0},
+ {"KP_3", 1},
+ {"³", 0},
+ {"eacute", 1},
+ {"ế", 0},
+ {"J", 1},
+ {"Ĵ", 0},
+ {"O", 1},
+ {"Ô", 0},
+ {"s", 1},
+ {"ŝ", 0},
+ {"Z", 1},
+ {"Ẑ", 0},
+ {"KP_0", 1},
+ {"⁰", 0},
+ {"A", 1},
+ {"Â", 0},
+ {"c", 1},
+ {"ĉ", 0},
+ {"KP_Add", 1},
+ {"⁺", 0},
+ {"KP_2", 1},
+ {"²", 0},
+ {"Cyrillic_A", 1},
+ {"А̂", 0},
+ {"dead_hook", 12},
+ {"a", 1},
+ {"ẩ", 0},
+ {"e", 1},
+ {"ể", 0},
+ {"o", 1},
+ {"ổ", 0},
+ {"E", 1},
+ {"Ể", 0},
+ {"O", 1},
+ {"Ổ", 0},
+ {"A", 1},
+ {"Ẩ", 0},
+ {"5", 1},
+ {"⁵", 0},
+ {"KP_5", 1},
+ {"⁵", 0},
+ {"9", 1},
+ {"⁹", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̂", 0},
+ {"Egrave", 1},
+ {"Ề", 0},
+ {"0", 1},
+ {"⁰", 0},
+ {"Aacute", 1},
+ {"Ấ", 0},
+ {"etilde", 1},
+ {"ễ", 0},
+ {"aacute", 1},
+ {"ấ", 0},
+ {"dead_acute", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Agrave", 1},
+ {"Ầ", 0},
+ {"parenleft", 1},
+ {"⁽", 0},
+ {"h", 1},
+ {"ĥ", 0},
+ {"I", 1},
+ {"Î", 0},
+ {"ehook", 1},
+ {"ể", 0},
+ {"U", 1},
+ {"Û", 0},
+ {"Cyrillic_u", 1},
+ {"у̂", 0},
+ {"KP_Equal", 1},
+ {"⁼", 0},
+ {"dead_currency", 103},
+ {"W", 1},
+ {"₩", 0},
+ {"g", 1},
+ {"₲", 0},
+ {"a", 1},
+ {"؋", 0},
+ {"dead_currency", 1},
+ {"¤", 0},
+ {"C", 1},
+ {"₡", 0},
+ {"e", 1},
+ {"€", 0},
+ {"F", 1},
+ {"₣", 0},
+ {"o", 1},
+ {"௹", 0},
+ {"l", 1},
+ {"£", 0},
+ {"t", 1},
+ {"৳", 0},
+ {"thorn", 1},
+ {"৲", 0},
+ {"space", 1},
+ {"¤", 0},
+ {"y", 1},
+ {"¥", 0},
+ {"b", 1},
+ {"฿", 0},
+ {"i", 1},
+ {"﷼", 0},
+ {"k", 1},
+ {"₭", 0},
+ {"n", 1},
+ {"₦", 0},
+ {"ccedilla", 1},
+ {"₵", 0},
+ {"nobreakspace", 1},
+ {"¤", 0},
+ {"u", 1},
+ {"元", 0},
+ {"G", 1},
+ {"₲", 0},
+ {"H", 1},
+ {"₴", 0},
+ {"E", 1},
+ {"₠", 0},
+ {"S", 1},
+ {"$", 0},
+ {"Y", 1},
+ {"円", 0},
+ {"f", 1},
+ {"ƒ", 0},
+ {"d", 1},
+ {"₫", 0},
+ {"D", 1},
+ {"₯", 0},
+ {"w", 1},
+ {"₩", 0},
+ {"p", 1},
+ {"₰", 0},
+ {"P", 1},
+ {"₧", 0},
+ {"M", 1},
+ {"ℳ", 0},
+ {"O", 1},
+ {"૱", 0},
+ {"m", 1},
+ {"₥", 0},
+ {"r", 1},
+ {"₢", 0},
+ {"s", 1},
+ {"₪", 0},
+ {"A", 1},
+ {"₳", 0},
+ {"R", 1},
+ {"₨", 0},
+ {"THORN", 1},
+ {"৲", 0},
+ {"c", 1},
+ {"¢", 0},
+ {"L", 1},
+ {"₤", 0},
+ {"T", 1},
+ {"₮", 0},
+ {"Ccedilla", 1},
+ {"₵", 0},
+ {"K", 1},
+ {"₭", 0},
+ {"B", 1},
+ {"₱", 0},
+ {"dead_cedilla", 4},
+ {"C", 1},
+ {"₵", 0},
+ {"c", 1},
+ {"₵", 0},
+ {"h", 1},
+ {"₴", 0},
+ {"I", 1},
+ {"៛", 0},
+ {"N", 1},
+ {"₦", 0},
+ {"U", 1},
+ {"圓", 0},
+ {"dead_belowdiaeresis", 7},
+ {"u", 1},
+ {"ṳ", 0},
+ {"dead_diaeresis", 2},
+ {"equal", 1},
+ {"⩷", 0},
+ {"U", 1},
+ {"Ṳ", 0},
+ {"dead_belowdot", 167},
+ {"minus", 1},
+ {"⨪", 0},
+ {"W", 1},
+ {"Ẉ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"a", 1},
+ {"ạ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ậ", 0},
+ {"e", 1},
+ {"ệ", 0},
+ {"o", 1},
+ {"ộ", 0},
+ {"E", 1},
+ {"Ệ", 0},
+ {"O", 1},
+ {"Ộ", 0},
+ {"A", 1},
+ {"Ậ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ợ", 0},
+ {"u", 1},
+ {"ự", 0},
+ {"O", 1},
+ {"Ợ", 0},
+ {"U", 1},
+ {"Ự", 0},
+ {"Acircumflex", 1},
+ {"Ậ", 0},
+ {"e", 1},
+ {"ẹ", 0},
+ {"o", 1},
+ {"ọ", 0},
+ {"l", 1},
+ {"ḷ", 0},
+ {"t", 1},
+ {"ṭ", 0},
+ {"dead_belowdot", 1},
+ {"̣", 0},
+ {"uhorn", 1},
+ {"ự", 0},
+ {"space", 1},
+ {"̣", 0},
+ {"dead_macron", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"acircumflex", 1},
+ {"ậ", 0},
+ {"Ecircumflex", 1},
+ {"Ệ", 0},
+ {"y", 1},
+ {"ỵ", 0},
+ {"b", 1},
+ {"ḅ", 0},
+ {"Multi_key", 9},
+ {"plus", 8},
+ {"o", 1},
+ {"ợ", 0},
+ {"u", 1},
+ {"ự", 0},
+ {"O", 1},
+ {"Ợ", 0},
+ {"U", 1},
+ {"Ự", 0},
+ {"i", 1},
+ {"ị", 0},
+ {"k", 1},
+ {"ḳ", 0},
+ {"n", 1},
+ {"ṇ", 0},
+ {"equal", 1},
+ {"⩦", 0},
+ {"Ohorn", 1},
+ {"Ợ", 0},
+ {"ohorn", 1},
+ {"ợ", 0},
+ {"sabovedot", 1},
+ {"ṩ", 0},
+ {"nobreakspace", 1},
+ {"̣", 0},
+ {"V", 1},
+ {"Ṿ", 0},
+ {"Ocircumflex", 1},
+ {"Ộ", 0},
+ {"ocircumflex", 1},
+ {"ộ", 0},
+ {"u", 1},
+ {"ụ", 0},
+ {"z", 1},
+ {"ẓ", 0},
+ {"H", 1},
+ {"Ḥ", 0},
+ {"E", 1},
+ {"Ẹ", 0},
+ {"S", 1},
+ {"Ṣ", 0},
+ {"Y", 1},
+ {"Ỵ", 0},
+ {"d", 1},
+ {"ḍ", 0},
+ {"D", 1},
+ {"Ḍ", 0},
+ {"Abreve", 1},
+ {"Ặ", 0},
+ {"plus", 1},
+ {"⨥", 0},
+ {"ecircumflex", 1},
+ {"ệ", 0},
+ {"dead_abovedot", 4},
+ {"S", 1},
+ {"Ṩ", 0},
+ {"s", 1},
+ {"ṩ", 0},
+ {"w", 1},
+ {"ẉ", 0},
+ {"v", 1},
+ {"ṿ", 0},
+ {"M", 1},
+ {"Ṃ", 0},
+ {"O", 1},
+ {"Ọ", 0},
+ {"abreve", 1},
+ {"ặ", 0},
+ {"m", 1},
+ {"ṃ", 0},
+ {"r", 1},
+ {"ṛ", 0},
+ {"s", 1},
+ {"ṣ", 0},
+ {"Z", 1},
+ {"Ẓ", 0},
+ {"A", 1},
+ {"Ạ", 0},
+ {"R", 1},
+ {"Ṛ", 0},
+ {"L", 1},
+ {"Ḷ", 0},
+ {"T", 1},
+ {"Ṭ", 0},
+ {"K", 1},
+ {"Ḳ", 0},
+ {"B", 1},
+ {"Ḅ", 0},
+ {"Sabovedot", 1},
+ {"Ṩ", 0},
+ {"Uhorn", 1},
+ {"Ự", 0},
+ {"h", 1},
+ {"ḥ", 0},
+ {"I", 1},
+ {"Ị", 0},
+ {"N", 1},
+ {"Ṇ", 0},
+ {"U", 1},
+ {"Ụ", 0},
+ {"dead_macron", 224},
+ {"adiaeresis", 1},
+ {"ǟ", 0},
+ {"g", 1},
+ {"ḡ", 0},
+ {"a", 1},
+ {"ā", 0},
+ {"Greek_IOTA", 1},
+ {"Ῑ", 0},
+ {"Ograve", 1},
+ {"Ṑ", 0},
+ {"dead_grave", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"Greek_iota", 1},
+ {"ῑ", 0},
+ {"Oacute", 1},
+ {"Ṓ", 0},
+ {"Cyrillic_er", 1},
+ {"р̄", 0},
+ {"e", 1},
+ {"ē", 0},
+ {"o", 1},
+ {"ō", 0},
+ {"Udiaeresis", 1},
+ {"Ǖ", 0},
+ {"Greek_upsilon", 1},
+ {"ῡ", 0},
+ {"dead_belowdot", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"space", 1},
+ {"¯", 0},
+ {"dead_macron", 1},
+ {"¯", 0},
+ {"Cyrillic_I", 1},
+ {"Ӣ", 0},
+ {"y", 1},
+ {"ȳ", 0},
+ {"Multi_key", 41},
+ {"period", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"exclam", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"quotedbl", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"asciitilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"semicolon", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"oacute", 1},
+ {"ṓ", 0},
+ {"Cyrillic_O", 1},
+ {"О̄", 0},
+ {"i", 1},
+ {"ī", 0},
+ {"dead_tilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"Cyrillic_a", 1},
+ {"а̄", 0},
+ {"Eacute", 1},
+ {"Ḗ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̄", 0},
+ {"Cyrillic_U", 1},
+ {"Ӯ", 0},
+ {"nobreakspace", 1},
+ {"̄", 0},
+ {"V", 1},
+ {"Ǖ", 0},
+ {"AE", 1},
+ {"Ǣ", 0},
+ {"u", 1},
+ {"ū", 0},
+ {"G", 1},
+ {"Ḡ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾱ", 0},
+ {"otilde", 1},
+ {"ȭ", 0},
+ {"Cyrillic_ie", 1},
+ {"е̄", 0},
+ {"E", 1},
+ {"Ē", 0},
+ {"Y", 1},
+ {"Ȳ", 0},
+ {"Cyrillic_i", 1},
+ {"ӣ", 0},
+ {"dead_ogonek", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"odiaeresis", 1},
+ {"ȫ", 0},
+ {"Otilde", 1},
+ {"Ȭ", 0},
+ {"egrave", 1},
+ {"ḕ", 0},
+ {"dead_greek", 12},
+ {"a", 1},
+ {"ᾱ", 0},
+ {"i", 1},
+ {"ῑ", 0},
+ {"u", 1},
+ {"ῡ", 0},
+ {"A", 1},
+ {"Ᾱ", 0},
+ {"I", 1},
+ {"Ῑ", 0},
+ {"U", 1},
+ {"Ῡ", 0},
+ {"ograve", 1},
+ {"ṑ", 0},
+ {"Greek_alpha", 1},
+ {"ᾱ", 0},
+ {"dead_abovedot", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"Cyrillic_o", 1},
+ {"о̄", 0},
+ {"eacute", 1},
+ {"ḗ", 0},
+ {"v", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ō", 0},
+ {"A", 1},
+ {"Ā", 0},
+ {"Odiaeresis", 1},
+ {"Ȫ", 0},
+ {"Cyrillic_A", 1},
+ {"А̄", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̄", 0},
+ {"Egrave", 1},
+ {"Ḕ", 0},
+ {"dead_diaeresis", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"Adiaeresis", 1},
+ {"Ǟ", 0},
+ {"dead_acute", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"udiaeresis", 1},
+ {"ǖ", 0},
+ {"I", 1},
+ {"Ī", 0},
+ {"U", 1},
+ {"Ū", 0},
+ {"Cyrillic_u", 1},
+ {"ӯ", 0},
+ {"ae", 1},
+ {"ǣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῡ", 0},
+ {"dead_doublegrave", 24},
+ {"Cyrillic_er", 1},
+ {"р̏", 0},
+ {"Cyrillic_I", 1},
+ {"И̏", 0},
+ {"Cyrillic_O", 1},
+ {"О̏", 0},
+ {"Cyrillic_a", 1},
+ {"а̏", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̏", 0},
+ {"Cyrillic_U", 1},
+ {"У̏", 0},
+ {"Cyrillic_ie", 1},
+ {"е̏", 0},
+ {"Cyrillic_i", 1},
+ {"и̏", 0},
+ {"Cyrillic_o", 1},
+ {"о̏", 0},
+ {"Cyrillic_A", 1},
+ {"А̏", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̏", 0},
+ {"Cyrillic_u", 1},
+ {"у̏", 0},
+ {"Multi_key", 5833},
+ {"backslash", 5},
+ {"minus", 1},
+ {"⍀", 0},
+ {"o", 2},
+ {"slash", 1},
+ {"🙌", 0},
+ {"minus", 59},
+ {"backslash", 1},
+ {"⍀", 0},
+ {"minus", 6},
+ {"minus", 1},
+ {"—", 0},
+ {"period", 1},
+ {"–", 0},
+ {"space", 1},
+ {"­", 0},
+ {"a", 1},
+ {"ā", 0},
+ {"e", 1},
+ {"ē", 0},
+ {"o", 1},
+ {"ō", 0},
+ {"l", 1},
+ {"£", 0},
+ {"space", 1},
+ {"~", 0},
+ {"y", 1},
+ {"¥", 0},
+ {"i", 1},
+ {"ī", 0},
+ {"parenright", 1},
+ {"}", 0},
+ {"u", 1},
+ {"ū", 0},
+ {"E", 1},
+ {"Ē", 0},
+ {"Y", 1},
+ {"¥", 0},
+ {"d", 1},
+ {"đ", 0},
+ {"D", 1},
+ {"Đ", 0},
+ {"plus", 1},
+ {"±", 0},
+ {"colon", 1},
+ {"÷", 0},
+ {"O", 1},
+ {"Ō", 0},
+ {"A", 1},
+ {"Ā", 0},
+ {"L", 1},
+ {"£", 0},
+ {"comma", 1},
+ {"¬", 0},
+ {"slash", 1},
+ {"⌿", 0},
+ {"greater", 1},
+ {"→", 0},
+ {"parenleft", 1},
+ {"{", 0},
+ {"I", 1},
+ {"Ī", 0},
+ {"U", 1},
+ {"Ū", 0},
+ {"asciicircum", 1},
+ {"¯", 0},
+ {"period", 130},
+ {"minus", 1},
+ {"·", 0},
+ {"period", 1},
+ {"…", 0},
+ {"W", 1},
+ {"Ẇ", 0},
+ {"g", 1},
+ {"ġ", 0},
+ {"a", 1},
+ {"ȧ", 0},
+ {"C", 1},
+ {"Ċ", 0},
+ {"exclam", 4},
+ {"S", 1},
+ {"Ṩ", 0},
+ {"s", 1},
+ {"ṩ", 0},
+ {"less", 1},
+ {"‹", 0},
+ {"e", 1},
+ {"ė", 0},
+ {"F", 1},
+ {"Ḟ", 0},
+ {"o", 1},
+ {"ȯ", 0},
+ {"t", 1},
+ {"ṫ", 0},
+ {"dead_belowdot", 4},
+ {"S", 1},
+ {"Ṩ", 0},
+ {"s", 1},
+ {"ṩ", 0},
+ {"y", 1},
+ {"ẏ", 0},
+ {"b", 1},
+ {"ḃ", 0},
+ {"i", 1},
+ {"ı", 0},
+ {"n", 1},
+ {"ṅ", 0},
+ {"equal", 1},
+ {"•", 0},
+ {"dead_caron", 4},
+ {"S", 1},
+ {"Ṧ", 0},
+ {"s", 1},
+ {"ṧ", 0},
+ {"x", 1},
+ {"ẋ", 0},
+ {"z", 1},
+ {"ż", 0},
+ {"G", 1},
+ {"Ġ", 0},
+ {"Sacute", 1},
+ {"Ṥ", 0},
+ {"H", 1},
+ {"Ḣ", 0},
+ {"E", 1},
+ {"Ė", 0},
+ {"S", 1},
+ {"Ṡ", 0},
+ {"Y", 1},
+ {"Ẏ", 0},
+ {"scaron", 1},
+ {"ṧ", 0},
+ {"f", 1},
+ {"ḟ", 0},
+ {"d", 1},
+ {"ḋ", 0},
+ {"Scaron", 1},
+ {"Ṧ", 0},
+ {"D", 1},
+ {"Ḋ", 0},
+ {"acute", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"w", 1},
+ {"ẇ", 0},
+ {"p", 1},
+ {"ṗ", 0},
+ {"P", 1},
+ {"Ṗ", 0},
+ {"apostrophe", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"M", 1},
+ {"Ṁ", 0},
+ {"O", 1},
+ {"Ȯ", 0},
+ {"m", 1},
+ {"ṁ", 0},
+ {"r", 1},
+ {"ṙ", 0},
+ {"s", 1},
+ {"ṡ", 0},
+ {"Z", 1},
+ {"Ż", 0},
+ {"sacute", 1},
+ {"ṥ", 0},
+ {"A", 1},
+ {"Ȧ", 0},
+ {"R", 1},
+ {"Ṙ", 0},
+ {"c", 1},
+ {"ċ", 0},
+ {"T", 1},
+ {"Ṫ", 0},
+ {"greater", 1},
+ {"›", 0},
+ {"B", 1},
+ {"Ḃ", 0},
+ {"dead_acute", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"X", 1},
+ {"Ẋ", 0},
+ {"h", 1},
+ {"ḣ", 0},
+ {"I", 1},
+ {"İ", 0},
+ {"N", 1},
+ {"Ṅ", 0},
+ {"asciicircum", 1},
+ {"·", 0},
+ {"W", 4},
+ {"equal", 1},
+ {"₩", 0},
+ {"asciicircum", 1},
+ {"Ŵ", 0},
+ {"g", 10},
+ {"period", 1},
+ {"ġ", 0},
+ {"breve", 1},
+ {"ğ", 0},
+ {"comma", 1},
+ {"ģ", 0},
+ {"parenleft", 1},
+ {"ğ", 0},
+ {"U", 1},
+ {"ğ", 0},
+ {"a", 30},
+ {"minus", 1},
+ {"ā", 0},
+ {"a", 1},
+ {"å", 0},
+ {"e", 1},
+ {"æ", 0},
+ {"diaeresis", 1},
+ {"ä", 0},
+ {"quotedbl", 1},
+ {"ä", 0},
+ {"acute", 1},
+ {"á", 0},
+ {"underscore", 1},
+ {"ā", 0},
+ {"apostrophe", 1},
+ {"á", 0},
+ {"asterisk", 1},
+ {"å", 0},
+ {"comma", 1},
+ {"ą", 0},
+ {"asciitilde", 1},
+ {"ã", 0},
+ {"greater", 1},
+ {"â", 0},
+ {"parenleft", 1},
+ {"ă", 0},
+ {"grave", 1},
+ {"à", 0},
+ {"asciicircum", 1},
+ {"â", 0},
+ {"Greek_IOTA", 4},
+ {"quotedbl", 1},
+ {"Ϊ", 0},
+ {"apostrophe", 1},
+ {"Ί", 0},
+ {"Greek_iota", 485},
+ {"dead_grave", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"Greek_eta", 1},
+ {"ῂ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"Greek_alpha", 1},
+ {"ᾲ", 0},
+ {"Greek_omega", 1},
+ {"ῲ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"dead_tilde", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"Greek_eta", 1},
+ {"ῇ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"Greek_alpha", 1},
+ {"ᾷ", 0},
+ {"Greek_omega", 1},
+ {"ῷ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾈ", 0},
+ {"Greek_eta", 1},
+ {"ᾐ", 0},
+ {"Greek_alpha", 1},
+ {"ᾀ", 0},
+ {"Greek_ETA", 1},
+ {"ᾘ", 0},
+ {"Greek_omega", 1},
+ {"ᾠ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾨ", 0},
+ {"Greek_ALPHA", 1},
+ {"ᾼ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾉ", 0},
+ {"Greek_eta", 1},
+ {"ᾑ", 0},
+ {"Greek_alpha", 1},
+ {"ᾁ", 0},
+ {"Greek_ETA", 1},
+ {"ᾙ", 0},
+ {"Greek_omega", 1},
+ {"ᾡ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾩ", 0},
+ {"Greek_eta", 1},
+ {"ῃ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾈ", 0},
+ {"Greek_eta", 1},
+ {"ᾐ", 0},
+ {"Greek_alpha", 1},
+ {"ᾀ", 0},
+ {"Greek_ETA", 1},
+ {"ᾘ", 0},
+ {"Greek_omega", 1},
+ {"ᾠ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾨ", 0},
+ {"quotedbl", 1},
+ {"ϊ", 0},
+ {"Greek_alpha", 1},
+ {"ᾳ", 0},
+ {"acute", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_ETA", 1},
+ {"ῌ", 0},
+ {"apostrophe", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_omegaaccent", 1},
+ {"ῴ", 0},
+ {"asciitilde", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"Greek_eta", 1},
+ {"ῇ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"Greek_alpha", 1},
+ {"ᾷ", 0},
+ {"Greek_omega", 1},
+ {"ῷ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"Greek_omega", 1},
+ {"ῳ", 0},
+ {"Greek_OMEGA", 1},
+ {"ῼ", 0},
+ {"dead_acute", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_alphaaccent", 1},
+ {"ᾴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾉ", 0},
+ {"Greek_eta", 1},
+ {"ᾑ", 0},
+ {"Greek_alpha", 1},
+ {"ᾁ", 0},
+ {"Greek_ETA", 1},
+ {"ᾙ", 0},
+ {"Greek_omega", 1},
+ {"ᾡ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾩ", 0},
+ {"grave", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"Greek_eta", 1},
+ {"ῂ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"Greek_alpha", 1},
+ {"ᾲ", 0},
+ {"Greek_omega", 1},
+ {"ῲ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"Greek_etaaccent", 1},
+ {"ῄ", 0},
+ {"1", 21},
+ {"1", 2},
+ {"0", 1},
+ {"⅒", 0},
+ {"7", 1},
+ {"⅐", 0},
+ {"8", 1},
+ {"⅛", 0},
+ {"3", 1},
+ {"⅓", 0},
+ {"2", 1},
+ {"½", 0},
+ {"6", 1},
+ {"⅙", 0},
+ {"4", 1},
+ {"¼", 0},
+ {"5", 1},
+ {"⅕", 0},
+ {"9", 1},
+ {"⅑", 0},
+ {"asciicircum", 1},
+ {"¹", 0},
+ {"Greek_OMICRON", 2},
+ {"apostrophe", 1},
+ {"Ό", 0},
+ {"C", 26},
+ {"period", 1},
+ {"Ċ", 0},
+ {"C", 3},
+ {"C", 2},
+ {"P", 1},
+ {"☭", 0},
+ {"less", 1},
+ {"Č", 0},
+ {"o", 1},
+ {"©", 0},
+ {"equal", 1},
+ {"€", 0},
+ {"E", 1},
+ {"₠", 0},
+ {"apostrophe", 1},
+ {"Ć", 0},
+ {"O", 1},
+ {"©", 0},
+ {"r", 1},
+ {"₢", 0},
+ {"bar", 1},
+ {"¢", 0},
+ {"comma", 1},
+ {"Ç", 0},
+ {"slash", 1},
+ {"₡", 0},
+ {"exclam", 108},
+ {"W", 1},
+ {"Ẉ", 0},
+ {"a", 1},
+ {"ạ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ợ", 0},
+ {"u", 1},
+ {"ự", 0},
+ {"O", 1},
+ {"Ợ", 0},
+ {"U", 1},
+ {"Ự", 0},
+ {"exclam", 1},
+ {"¡", 0},
+ {"e", 1},
+ {"ẹ", 0},
+ {"o", 1},
+ {"ọ", 0},
+ {"l", 1},
+ {"ḷ", 0},
+ {"t", 1},
+ {"ṭ", 0},
+ {"uhorn", 1},
+ {"ự", 0},
+ {"y", 1},
+ {"ỵ", 0},
+ {"b", 1},
+ {"ḅ", 0},
+ {"i", 1},
+ {"ị", 0},
+ {"k", 1},
+ {"ḳ", 0},
+ {"n", 1},
+ {"ṇ", 0},
+ {"Ohorn", 1},
+ {"Ợ", 0},
+ {"ohorn", 1},
+ {"ợ", 0},
+ {"V", 1},
+ {"Ṿ", 0},
+ {"u", 1},
+ {"ụ", 0},
+ {"z", 1},
+ {"ẓ", 0},
+ {"H", 1},
+ {"Ḥ", 0},
+ {"E", 1},
+ {"Ẹ", 0},
+ {"S", 1},
+ {"Ṣ", 0},
+ {"Y", 1},
+ {"Ỵ", 0},
+ {"d", 1},
+ {"ḍ", 0},
+ {"D", 1},
+ {"Ḍ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ợ", 0},
+ {"u", 1},
+ {"ự", 0},
+ {"O", 1},
+ {"Ợ", 0},
+ {"U", 1},
+ {"Ự", 0},
+ {"w", 1},
+ {"ẉ", 0},
+ {"v", 1},
+ {"ṿ", 0},
+ {"question", 1},
+ {"‽", 0},
+ {"M", 1},
+ {"Ṃ", 0},
+ {"O", 1},
+ {"Ọ", 0},
+ {"m", 1},
+ {"ṃ", 0},
+ {"r", 1},
+ {"ṛ", 0},
+ {"s", 1},
+ {"ṣ", 0},
+ {"Z", 1},
+ {"Ẓ", 0},
+ {"A", 1},
+ {"Ạ", 0},
+ {"R", 1},
+ {"Ṛ", 0},
+ {"L", 1},
+ {"Ḷ", 0},
+ {"T", 1},
+ {"Ṭ", 0},
+ {"K", 1},
+ {"Ḳ", 0},
+ {"B", 1},
+ {"Ḅ", 0},
+ {"Uhorn", 1},
+ {"Ự", 0},
+ {"h", 1},
+ {"ḥ", 0},
+ {"I", 1},
+ {"Ị", 0},
+ {"N", 1},
+ {"Ṇ", 0},
+ {"U", 1},
+ {"Ụ", 0},
+ {"asciicircum", 1},
+ {"¦", 0},
+ {"less", 56},
+ {"minus", 1},
+ {"←", 0},
+ {"C", 1},
+ {"Č", 0},
+ {"less", 1},
+ {"«", 0},
+ {"e", 1},
+ {"ě", 0},
+ {"l", 1},
+ {"ľ", 0},
+ {"t", 1},
+ {"ť", 0},
+ {"space", 1},
+ {"ˇ", 0},
+ {"n", 1},
+ {"ň", 0},
+ {"equal", 1},
+ {"≤", 0},
+ {"z", 1},
+ {"ž", 0},
+ {"3", 1},
+ {"♥", 0},
+ {"E", 1},
+ {"Ě", 0},
+ {"S", 1},
+ {"Š", 0},
+ {"d", 1},
+ {"ď", 0},
+ {"D", 1},
+ {"Ď", 0},
+ {"quotedbl", 1},
+ {"“", 0},
+ {"underscore", 1},
+ {"≤", 0},
+ {"apostrophe", 1},
+ {"‘", 0},
+ {"r", 1},
+ {"ř", 0},
+ {"s", 1},
+ {"š", 0},
+ {"Z", 1},
+ {"Ž", 0},
+ {"R", 1},
+ {"Ř", 0},
+ {"c", 1},
+ {"č", 0},
+ {"L", 1},
+ {"Ľ", 0},
+ {"T", 1},
+ {"Ť", 0},
+ {"slash", 1},
+ {"\\", 0},
+ {"greater", 1},
+ {"⋄", 0},
+ {"N", 1},
+ {"Ň", 0},
+ {"KP_Divide", 46},
+ {"g", 1},
+ {"ǥ", 0},
+ {"o", 1},
+ {"ø", 0},
+ {"l", 1},
+ {"ł", 0},
+ {"t", 1},
+ {"ŧ", 0},
+ {"b", 1},
+ {"ƀ", 0},
+ {"i", 1},
+ {"ɨ", 0},
+ {"Cyrillic_GHE", 1},
+ {"Ғ", 0},
+ {"leftarrow", 1},
+ {"↚", 0},
+ {"Cyrillic_KA", 1},
+ {"Ҟ", 0},
+ {"rightarrow", 1},
+ {"↛", 0},
+ {"z", 1},
+ {"ƶ", 0},
+ {"G", 1},
+ {"Ǥ", 0},
+ {"H", 1},
+ {"Ħ", 0},
+ {"d", 1},
+ {"đ", 0},
+ {"Cyrillic_ka", 1},
+ {"ҟ", 0},
+ {"D", 1},
+ {"Đ", 0},
+ {"O", 1},
+ {"Ø", 0},
+ {"Z", 1},
+ {"Ƶ", 0},
+ {"L", 1},
+ {"Ł", 0},
+ {"T", 1},
+ {"Ŧ", 0},
+ {"Cyrillic_ghe", 1},
+ {"ғ", 0},
+ {"h", 1},
+ {"ħ", 0},
+ {"I", 1},
+ {"Ɨ", 0},
+ {"F", 8},
+ {"period", 1},
+ {"Ḟ", 0},
+ {"l", 1},
+ {"ffl", 0},
+ {"i", 1},
+ {"ffi", 0},
+ {"r", 1},
+ {"₣", 0},
+ {"e", 28},
+ {"minus", 1},
+ {"ē", 0},
+ {"period", 1},
+ {"ė", 0},
+ {"less", 1},
+ {"ě", 0},
+ {"e", 1},
+ {"ə", 0},
+ {"diaeresis", 1},
+ {"ë", 0},
+ {"equal", 1},
+ {"€", 0},
+ {"quotedbl", 1},
+ {"ë", 0},
+ {"acute", 1},
+ {"é", 0},
+ {"underscore", 1},
+ {"ē", 0},
+ {"apostrophe", 1},
+ {"é", 0},
+ {"comma", 1},
+ {"ę", 0},
+ {"greater", 1},
+ {"ê", 0},
+ {"grave", 1},
+ {"è", 0},
+ {"asciicircum", 1},
+ {"ê", 0},
+ {"o", 52},
+ {"minus", 1},
+ {"ō", 0},
+ {"a", 1},
+ {"å", 0},
+ {"C", 1},
+ {"©", 0},
+ {"e", 1},
+ {"œ", 0},
+ {"o", 1},
+ {"°", 0},
+ {"diaeresis", 1},
+ {"ö", 0},
+ {"y", 1},
+ {"ẙ", 0},
+ {"x", 1},
+ {"¤", 0},
+ {"u", 1},
+ {"ů", 0},
+ {"quotedbl", 1},
+ {"ö", 0},
+ {"acute", 1},
+ {"ó", 0},
+ {"w", 1},
+ {"ẘ", 0},
+ {"underscore", 1},
+ {"ō", 0},
+ {"apostrophe", 1},
+ {"ó", 0},
+ {"r", 1},
+ {"®", 0},
+ {"s", 1},
+ {"§", 0},
+ {"A", 1},
+ {"Å", 0},
+ {"R", 1},
+ {"®", 0},
+ {"c", 1},
+ {"©", 0},
+ {"asciitilde", 1},
+ {"õ", 0},
+ {"slash", 1},
+ {"ø", 0},
+ {"greater", 1},
+ {"ô", 0},
+ {"X", 1},
+ {"¤", 0},
+ {"grave", 1},
+ {"ò", 0},
+ {"U", 1},
+ {"Ů", 0},
+ {"asciicircum", 1},
+ {"ô", 0},
+ {"l", 12},
+ {"minus", 1},
+ {"£", 0},
+ {"less", 1},
+ {"ľ", 0},
+ {"v", 1},
+ {"|", 0},
+ {"apostrophe", 1},
+ {"ĺ", 0},
+ {"comma", 1},
+ {"ļ", 0},
+ {"slash", 1},
+ {"ł", 0},
+ {"Greek_upsilon", 4},
+ {"quotedbl", 1},
+ {"ϋ", 0},
+ {"apostrophe", 1},
+ {"ύ", 0},
+ {"t", 16},
+ {"minus", 1},
+ {"ŧ", 0},
+ {"period", 1},
+ {"ṫ", 0},
+ {"less", 1},
+ {"ť", 0},
+ {"M", 1},
+ {"™", 0},
+ {"m", 1},
+ {"™", 0},
+ {"comma", 1},
+ {"ţ", 0},
+ {"slash", 1},
+ {"ŧ", 0},
+ {"h", 1},
+ {"þ", 0},
+ {"diaeresis", 42},
+ {"a", 1},
+ {"ä", 0},
+ {"dead_grave", 1},
+ {"῭", 0},
+ {"e", 1},
+ {"ë", 0},
+ {"o", 1},
+ {"ö", 0},
+ {"y", 1},
+ {"ÿ", 0},
+ {"i", 1},
+ {"ï", 0},
+ {"dead_tilde", 1},
+ {"῁", 0},
+ {"u", 1},
+ {"ü", 0},
+ {"E", 1},
+ {"Ë", 0},
+ {"Y", 1},
+ {"Ÿ", 0},
+ {"acute", 1},
+ {"΅", 0},
+ {"apostrophe", 1},
+ {"΅", 0},
+ {"O", 1},
+ {"Ö", 0},
+ {"asterisk", 1},
+ {"⍣", 0},
+ {"A", 1},
+ {"Ä", 0},
+ {"asciitilde", 1},
+ {"῁", 0},
+ {"greater", 1},
+ {"⍩", 0},
+ {"dead_acute", 1},
+ {"΅", 0},
+ {"I", 1},
+ {"Ï", 0},
+ {"grave", 1},
+ {"῭", 0},
+ {"U", 1},
+ {"Ü", 0},
+ {"space", 22},
+ {"minus", 1},
+ {"~", 0},
+ {"period", 1},
+ {" ", 0},
+ {"less", 1},
+ {"ˇ", 0},
+ {"space", 1},
+ {" ", 0},
+ {"apostrophe", 1},
+ {"'", 0},
+ {"comma", 1},
+ {"¸", 0},
+ {"asciitilde", 1},
+ {"~", 0},
+ {"greater", 1},
+ {"^", 0},
+ {"parenleft", 1},
+ {"˘", 0},
+ {"grave", 1},
+ {"`", 0},
+ {"asciicircum", 1},
+ {"^", 0},
+ {"percent", 2},
+ {"o", 1},
+ {"‰", 0},
+ {"y", 14},
+ {"minus", 1},
+ {"¥", 0},
+ {"diaeresis", 1},
+ {"ÿ", 0},
+ {"equal", 1},
+ {"¥", 0},
+ {"quotedbl", 1},
+ {"ÿ", 0},
+ {"acute", 1},
+ {"ý", 0},
+ {"apostrophe", 1},
+ {"ý", 0},
+ {"asciicircum", 1},
+ {"ŷ", 0},
+ {"b", 83},
+ {"period", 1},
+ {"ḃ", 0},
+ {"g", 1},
+ {"ğ", 0},
+ {"a", 1},
+ {"ă", 0},
+ {"Greek_IOTA", 1},
+ {"Ῐ", 0},
+ {"Greek_iota", 1},
+ {"ῐ", 0},
+ {"exclam", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"e", 1},
+ {"ĕ", 0},
+ {"o", 1},
+ {"ŏ", 0},
+ {"Greek_upsilon", 1},
+ {"ῠ", 0},
+ {"dead_belowdot", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"Cyrillic_I", 1},
+ {"Й", 0},
+ {"i", 1},
+ {"ĭ", 0},
+ {"Cyrillic_a", 1},
+ {"ӑ", 0},
+ {"Cyrillic_U", 1},
+ {"Ў", 0},
+ {"u", 1},
+ {"ŭ", 0},
+ {"G", 1},
+ {"Ğ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾰ", 0},
+ {"Cyrillic_ie", 1},
+ {"ӗ", 0},
+ {"E", 1},
+ {"Ĕ", 0},
+ {"Cyrillic_i", 1},
+ {"й", 0},
+ {"Cyrillic_zhe", 1},
+ {"ӂ", 0},
+ {"cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"Greek_alpha", 1},
+ {"ᾰ", 0},
+ {"O", 1},
+ {"Ŏ", 0},
+ {"A", 1},
+ {"Ă", 0},
+ {"Cyrillic_A", 1},
+ {"Ӑ", 0},
+ {"comma", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"Cyrillic_ZHE", 1},
+ {"Ӂ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ӗ", 0},
+ {"dead_cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"I", 1},
+ {"Ĭ", 0},
+ {"U", 1},
+ {"Ŭ", 0},
+ {"Cyrillic_u", 1},
+ {"ў", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῠ", 0},
+ {"i", 28},
+ {"minus", 1},
+ {"ī", 0},
+ {"period", 1},
+ {"ı", 0},
+ {"diaeresis", 1},
+ {"ï", 0},
+ {"j", 1},
+ {"ij", 0},
+ {"quotedbl", 1},
+ {"ï", 0},
+ {"acute", 1},
+ {"í", 0},
+ {"underscore", 1},
+ {"ī", 0},
+ {"apostrophe", 1},
+ {"í", 0},
+ {"comma", 1},
+ {"į", 0},
+ {"asciitilde", 1},
+ {"ĩ", 0},
+ {"greater", 1},
+ {"î", 0},
+ {"semicolon", 1},
+ {"į", 0},
+ {"grave", 1},
+ {"ì", 0},
+ {"asciicircum", 1},
+ {"î", 0},
+ {"k", 4},
+ {"k", 1},
+ {"ĸ", 0},
+ {"comma", 1},
+ {"ķ", 0},
+ {"n", 10},
+ {"g", 1},
+ {"ŋ", 0},
+ {"less", 1},
+ {"ň", 0},
+ {"apostrophe", 1},
+ {"ń", 0},
+ {"comma", 1},
+ {"ņ", 0},
+ {"asciitilde", 1},
+ {"ñ", 0},
+ {"equal", 40},
+ {"W", 1},
+ {"₩", 0},
+ {"C", 1},
+ {"€", 0},
+ {"e", 1},
+ {"€", 0},
+ {"o", 1},
+ {"ő", 0},
+ {"y", 1},
+ {"¥", 0},
+ {"Cyrillic_U", 1},
+ {"Ӳ", 0},
+ {"u", 1},
+ {"ű", 0},
+ {"E", 1},
+ {"€", 0},
+ {"Y", 1},
+ {"¥", 0},
+ {"d", 1},
+ {"₫", 0},
+ {"underscore", 1},
+ {"≡", 0},
+ {"O", 1},
+ {"Ő", 0},
+ {"Cyrillic_ES", 1},
+ {"€", 0},
+ {"c", 1},
+ {"€", 0},
+ {"L", 1},
+ {"₤", 0},
+ {"slash", 1},
+ {"≠", 0},
+ {"Cyrillic_IE", 1},
+ {"€", 0},
+ {"N", 1},
+ {"₦", 0},
+ {"U", 1},
+ {"Ű", 0},
+ {"Cyrillic_u", 1},
+ {"ӳ", 0},
+ {"7", 2},
+ {"8", 1},
+ {"⅞", 0},
+ {"parenright", 32},
+ {"minus", 1},
+ {"}", 0},
+ {"Greek_IOTA", 1},
+ {"Ἰ", 0},
+ {"Greek_iota", 1},
+ {"ἰ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὀ", 0},
+ {"Greek_upsilon", 1},
+ {"ὐ", 0},
+ {"parenright", 1},
+ {"]", 0},
+ {"Greek_epsilon", 1},
+ {"ἐ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἀ", 0},
+ {"Greek_omicron", 1},
+ {"ὀ", 0},
+ {"Greek_eta", 1},
+ {"ἠ", 0},
+ {"Greek_rho", 1},
+ {"ῤ", 0},
+ {"Greek_alpha", 1},
+ {"ἀ", 0},
+ {"Greek_ETA", 1},
+ {"Ἠ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἐ", 0},
+ {"Greek_omega", 1},
+ {"ὠ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὠ", 0},
+ {"x", 6},
+ {"o", 1},
+ {"¤", 0},
+ {"x", 1},
+ {"×", 0},
+ {"O", 1},
+ {"¤", 0},
+ {"Greek_epsilon", 2},
+ {"apostrophe", 1},
+ {"έ", 0},
+ {"braceleft", 2},
+ {"braceright", 1},
+ {"∅", 0},
+ {"underbar", 54},
+ {"1", 1},
+ {"₁", 0},
+ {"KP_4", 1},
+ {"₄", 0},
+ {"KP_6", 1},
+ {"₆", 0},
+ {"KP_8", 1},
+ {"₈", 0},
+ {"KP_9", 1},
+ {"₉", 0},
+ {"equal", 1},
+ {"₌", 0},
+ {"KP_Space", 1},
+ {"₂", 0},
+ {"7", 1},
+ {"₇", 0},
+ {"parenright", 1},
+ {"₎", 0},
+ {"KP_7", 1},
+ {"₇", 0},
+ {"8", 1},
+ {"₈", 0},
+ {"KP_1", 1},
+ {"₁", 0},
+ {"3", 1},
+ {"₃", 0},
+ {"2", 1},
+ {"₂", 0},
+ {"plus", 1},
+ {"₊", 0},
+ {"6", 1},
+ {"₆", 0},
+ {"4", 1},
+ {"₄", 0},
+ {"KP_3", 1},
+ {"₃", 0},
+ {"KP_0", 1},
+ {"₀", 0},
+ {"KP_Add", 1},
+ {"₊", 0},
+ {"KP_2", 1},
+ {"₂", 0},
+ {"5", 1},
+ {"₅", 0},
+ {"KP_5", 1},
+ {"₅", 0},
+ {"9", 1},
+ {"₉", 0},
+ {"0", 1},
+ {"₀", 0},
+ {"parenleft", 1},
+ {"₍", 0},
+ {"KP_Equal", 1},
+ {"₌", 0},
+ {"V", 2},
+ {"L", 1},
+ {"|", 0},
+ {"u", 28},
+ {"minus", 1},
+ {"ū", 0},
+ {"diaeresis", 1},
+ {"ü", 0},
+ {"u", 1},
+ {"ŭ", 0},
+ {"quotedbl", 1},
+ {"ü", 0},
+ {"acute", 1},
+ {"ú", 0},
+ {"underscore", 1},
+ {"ū", 0},
+ {"apostrophe", 1},
+ {"ú", 0},
+ {"asterisk", 1},
+ {"ů", 0},
+ {"comma", 1},
+ {"ų", 0},
+ {"asciitilde", 1},
+ {"ũ", 0},
+ {"slash", 1},
+ {"µ", 0},
+ {"greater", 1},
+ {"û", 0},
+ {"grave", 1},
+ {"ù", 0},
+ {"asciicircum", 1},
+ {"û", 0},
+ {"breve", 4},
+ {"g", 1},
+ {"ğ", 0},
+ {"G", 1},
+ {"Ğ", 0},
+ {"z", 6},
+ {"period", 1},
+ {"ż", 0},
+ {"less", 1},
+ {"ž", 0},
+ {"apostrophe", 1},
+ {"ź", 0},
+ {"G", 10},
+ {"period", 1},
+ {"Ġ", 0},
+ {"breve", 1},
+ {"Ğ", 0},
+ {"comma", 1},
+ {"Ģ", 0},
+ {"parenleft", 1},
+ {"Ğ", 0},
+ {"U", 1},
+ {"Ğ", 0},
+ {"Greek_ALPHA", 2},
+ {"apostrophe", 1},
+ {"Ά", 0},
+ {"bracketleft", 2},
+ {"bracketright", 1},
+ {"⌷", 0},
+ {"H", 2},
+ {"comma", 1},
+ {"Ḩ", 0},
+ {"8", 2},
+ {"8", 1},
+ {"∞", 0},
+ {"3", 8},
+ {"8", 1},
+ {"⅜", 0},
+ {"4", 1},
+ {"¾", 0},
+ {"5", 1},
+ {"⅗", 0},
+ {"asciicircum", 1},
+ {"³", 0},
+ {"E", 26},
+ {"minus", 1},
+ {"Ē", 0},
+ {"period", 1},
+ {"Ė", 0},
+ {"less", 1},
+ {"Ě", 0},
+ {"diaeresis", 1},
+ {"Ë", 0},
+ {"equal", 1},
+ {"€", 0},
+ {"quotedbl", 1},
+ {"Ë", 0},
+ {"acute", 1},
+ {"É", 0},
+ {"underscore", 1},
+ {"Ē", 0},
+ {"apostrophe", 1},
+ {"É", 0},
+ {"comma", 1},
+ {"Ę", 0},
+ {"greater", 1},
+ {"Ê", 0},
+ {"grave", 1},
+ {"È", 0},
+ {"asciicircum", 1},
+ {"Ê", 0},
+ {"S", 18},
+ {"period", 1},
+ {"Ṡ", 0},
+ {"exclam", 1},
+ {"§", 0},
+ {"less", 1},
+ {"Š", 0},
+ {"S", 1},
+ {"ẞ", 0},
+ {"apostrophe", 1},
+ {"Ś", 0},
+ {"M", 1},
+ {"℠", 0},
+ {"O", 1},
+ {"§", 0},
+ {"m", 1},
+ {"℠", 0},
+ {"comma", 1},
+ {"Ş", 0},
+ {"2", 6},
+ {"3", 1},
+ {"⅔", 0},
+ {"5", 1},
+ {"⅖", 0},
+ {"asciicircum", 1},
+ {"²", 0},
+ {"Y", 14},
+ {"minus", 1},
+ {"¥", 0},
+ {"diaeresis", 1},
+ {"Ÿ", 0},
+ {"equal", 1},
+ {"¥", 0},
+ {"quotedbl", 1},
+ {"Ÿ", 0},
+ {"acute", 1},
+ {"Ý", 0},
+ {"apostrophe", 1},
+ {"Ý", 0},
+ {"asciicircum", 1},
+ {"Ŷ", 0},
+ {"f", 12},
+ {"period", 1},
+ {"ḟ", 0},
+ {"l", 1},
+ {"fl", 0},
+ {"i", 1},
+ {"fi", 0},
+ {"S", 1},
+ {"ſ", 0},
+ {"f", 1},
+ {"ff", 0},
+ {"s", 1},
+ {"ſ", 0},
+ {"Greek_omicron", 2},
+ {"apostrophe", 1},
+ {"ό", 0},
+ {"Greek_eta", 2},
+ {"apostrophe", 1},
+ {"ή", 0},
+ {"d", 14},
+ {"minus", 1},
+ {"đ", 0},
+ {"period", 1},
+ {"ḋ", 0},
+ {"less", 1},
+ {"ď", 0},
+ {"i", 1},
+ {"⌀", 0},
+ {"equal", 1},
+ {"₫", 0},
+ {"comma", 1},
+ {"ḑ", 0},
+ {"h", 1},
+ {"ð", 0},
+ {"D", 10},
+ {"minus", 1},
+ {"Đ", 0},
+ {"period", 1},
+ {"Ḋ", 0},
+ {"less", 1},
+ {"Ď", 0},
+ {"H", 1},
+ {"Ð", 0},
+ {"comma", 1},
+ {"Ḑ", 0},
+ {"quotedbl", 137},
+ {"W", 1},
+ {"Ẅ", 0},
+ {"a", 1},
+ {"ä", 0},
+ {"Greek_IOTA", 1},
+ {"Ϊ", 0},
+ {"Greek_iota", 1},
+ {"ϊ", 0},
+ {"less", 1},
+ {"“", 0},
+ {"Umacron", 1},
+ {"Ṻ", 0},
+ {"Cyrillic_ZE", 1},
+ {"Ӟ", 0},
+ {"e", 1},
+ {"ë", 0},
+ {"o", 1},
+ {"ö", 0},
+ {"Cyrillic_ze", 1},
+ {"ӟ", 0},
+ {"t", 1},
+ {"ẗ", 0},
+ {"Greek_upsilon", 1},
+ {"ϋ", 0},
+ {"dead_macron", 4},
+ {"u", 1},
+ {"ṻ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"Cyrillic_I", 1},
+ {"Ӥ", 0},
+ {"y", 1},
+ {"ÿ", 0},
+ {"Cyrillic_O", 1},
+ {"Ӧ", 0},
+ {"i", 1},
+ {"ï", 0},
+ {"Ukrainian_I", 1},
+ {"Ї", 0},
+ {"dead_tilde", 4},
+ {"o", 1},
+ {"ṏ", 0},
+ {"O", 1},
+ {"Ṏ", 0},
+ {"Cyrillic_che", 1},
+ {"ӵ", 0},
+ {"Cyrillic_a", 1},
+ {"ӓ", 0},
+ {"x", 1},
+ {"ẍ", 0},
+ {"Cyrillic_U", 1},
+ {"Ӱ", 0},
+ {"u", 1},
+ {"ü", 0},
+ {"otilde", 1},
+ {"ṏ", 0},
+ {"H", 1},
+ {"Ḧ", 0},
+ {"Cyrillic_YERU", 1},
+ {"Ӹ", 0},
+ {"Cyrillic_ie", 1},
+ {"ё", 0},
+ {"E", 1},
+ {"Ë", 0},
+ {"Y", 1},
+ {"Ÿ", 0},
+ {"Cyrillic_i", 1},
+ {"ӥ", 0},
+ {"Otilde", 1},
+ {"Ṏ", 0},
+ {"Cyrillic_zhe", 1},
+ {"ӝ", 0},
+ {"quotedbl", 1},
+ {"¨", 0},
+ {"umacron", 1},
+ {"ṻ", 0},
+ {"Cyrillic_yeru", 1},
+ {"ӹ", 0},
+ {"acute", 1},
+ {"̈́", 0},
+ {"w", 1},
+ {"ẅ", 0},
+ {"Cyrillic_CHE", 1},
+ {"Ӵ", 0},
+ {"Cyrillic_o", 1},
+ {"ӧ", 0},
+ {"Ukrainian_i", 1},
+ {"ї", 0},
+ {"Cyrillic_E", 1},
+ {"Ӭ", 0},
+ {"underscore", 4},
+ {"u", 1},
+ {"ṻ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"apostrophe", 1},
+ {"̈́", 0},
+ {"O", 1},
+ {"Ö", 0},
+ {"macron", 4},
+ {"u", 1},
+ {"ṻ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"A", 1},
+ {"Ä", 0},
+ {"Cyrillic_A", 1},
+ {"Ӓ", 0},
+ {"comma", 1},
+ {"„", 0},
+ {"asciitilde", 4},
+ {"o", 1},
+ {"ṏ", 0},
+ {"O", 1},
+ {"Ṏ", 0},
+ {"greater", 1},
+ {"”", 0},
+ {"Cyrillic_ZHE", 1},
+ {"Ӝ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ё", 0},
+ {"Cyrillic_e", 1},
+ {"ӭ", 0},
+ {"dead_acute", 1},
+ {"̈́", 0},
+ {"X", 1},
+ {"Ẍ", 0},
+ {"h", 1},
+ {"ḧ", 0},
+ {"I", 1},
+ {"Ï", 0},
+ {"U", 1},
+ {"Ü", 0},
+ {"Cyrillic_u", 1},
+ {"ӱ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ϋ", 0},
+ {"plus", 12},
+ {"minus", 1},
+ {"±", 0},
+ {"o", 1},
+ {"ơ", 0},
+ {"u", 1},
+ {"ư", 0},
+ {"plus", 1},
+ {"#", 0},
+ {"O", 1},
+ {"Ơ", 0},
+ {"U", 1},
+ {"Ư", 0},
+ {"cedilla", 44},
+ {"g", 1},
+ {"ģ", 0},
+ {"C", 1},
+ {"Ç", 0},
+ {"e", 1},
+ {"ȩ", 0},
+ {"l", 1},
+ {"ļ", 0},
+ {"t", 1},
+ {"ţ", 0},
+ {"k", 1},
+ {"ķ", 0},
+ {"n", 1},
+ {"ņ", 0},
+ {"G", 1},
+ {"Ģ", 0},
+ {"H", 1},
+ {"Ḩ", 0},
+ {"E", 1},
+ {"Ȩ", 0},
+ {"S", 1},
+ {"Ş", 0},
+ {"d", 1},
+ {"ḑ", 0},
+ {"D", 1},
+ {"Ḑ", 0},
+ {"r", 1},
+ {"ŗ", 0},
+ {"s", 1},
+ {"ş", 0},
+ {"R", 1},
+ {"Ŗ", 0},
+ {"c", 1},
+ {"ç", 0},
+ {"L", 1},
+ {"Ļ", 0},
+ {"T", 1},
+ {"Ţ", 0},
+ {"K", 1},
+ {"Ķ", 0},
+ {"h", 1},
+ {"ḩ", 0},
+ {"N", 1},
+ {"Ņ", 0},
+ {"Greek_alpha", 2},
+ {"apostrophe", 1},
+ {"ά", 0},
+ {"dead_abovedot", 3},
+ {"f", 2},
+ {"s", 1},
+ {"ẛ", 0},
+ {"acute", 463},
+ {"W", 1},
+ {"Ẃ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"g", 1},
+ {"ǵ", 0},
+ {"a", 1},
+ {"á", 0},
+ {"Greek_IOTA", 1},
+ {"Ί", 0},
+ {"Greek_iota", 1},
+ {"ί", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ό", 0},
+ {"Acircumflex", 1},
+ {"Ấ", 0},
+ {"C", 1},
+ {"Ć", 0},
+ {"Cyrillic_er", 1},
+ {"р́", 0},
+ {"e", 1},
+ {"é", 0},
+ {"KP_Divide", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"Utilde", 1},
+ {"Ṹ", 0},
+ {"o", 1},
+ {"ó", 0},
+ {"l", 1},
+ {"ĺ", 0},
+ {"Udiaeresis", 1},
+ {"Ǘ", 0},
+ {"Greek_upsilon", 1},
+ {"ύ", 0},
+ {"uhorn", 1},
+ {"ứ", 0},
+ {"dead_macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"acircumflex", 1},
+ {"ấ", 0},
+ {"Ecircumflex", 1},
+ {"Ế", 0},
+ {"Cyrillic_I", 1},
+ {"И́", 0},
+ {"y", 1},
+ {"ý", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"idiaeresis", 1},
+ {"ḯ", 0},
+ {"Cyrillic_O", 1},
+ {"О́", 0},
+ {"i", 1},
+ {"í", 0},
+ {"k", 1},
+ {"ḱ", 0},
+ {"n", 1},
+ {"ń", 0},
+ {"ccedilla", 1},
+ {"ḉ", 0},
+ {"Cyrillic_GHE", 1},
+ {"Ѓ", 0},
+ {"dead_tilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"Cyrillic_a", 1},
+ {"а́", 0},
+ {"parenright", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"Ohorn", 1},
+ {"Ớ", 0},
+ {"ohorn", 1},
+ {"ớ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р́", 0},
+ {"Greek_epsilon", 1},
+ {"έ", 0},
+ {"Cyrillic_KA", 1},
+ {"Ќ", 0},
+ {"Cyrillic_U", 1},
+ {"У́", 0},
+ {"dead_abovering", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"Ocircumflex", 1},
+ {"Ố", 0},
+ {"AE", 1},
+ {"Ǽ", 0},
+ {"omacron", 1},
+ {"ṓ", 0},
+ {"ocircumflex", 1},
+ {"ố", 0},
+ {"u", 1},
+ {"ú", 0},
+ {"z", 1},
+ {"ź", 0},
+ {"G", 1},
+ {"Ǵ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ά", 0},
+ {"otilde", 1},
+ {"ṍ", 0},
+ {"utilde", 1},
+ {"ṹ", 0},
+ {"Cyrillic_ie", 1},
+ {"е́", 0},
+ {"emacron", 1},
+ {"ḗ", 0},
+ {"E", 1},
+ {"É", 0},
+ {"S", 1},
+ {"Ś", 0},
+ {"Greek_iotadieresis", 1},
+ {"ΐ", 0},
+ {"Y", 1},
+ {"Ý", 0},
+ {"Cyrillic_i", 1},
+ {"и́", 0},
+ {"dead_dasia", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ΰ", 0},
+ {"Greek_omicron", 1},
+ {"ό", 0},
+ {"Greek_eta", 1},
+ {"ή", 0},
+ {"Otilde", 1},
+ {"Ṍ", 0},
+ {"Cyrillic_ka", 1},
+ {"ќ", 0},
+ {"Aring", 1},
+ {"Ǻ", 0},
+ {"Abreve", 1},
+ {"Ắ", 0},
+ {"dead_psili", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"quotedbl", 12},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"Greek_alpha", 1},
+ {"ά", 0},
+ {"ecircumflex", 1},
+ {"ế", 0},
+ {"w", 1},
+ {"ẃ", 0},
+ {"Greek_ETA", 1},
+ {"Ή", 0},
+ {"Cyrillic_o", 1},
+ {"о́", 0},
+ {"Emacron", 1},
+ {"Ḗ", 0},
+ {"Ooblique", 1},
+ {"Ǿ", 0},
+ {"p", 1},
+ {"ṕ", 0},
+ {"underscore", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"P", 1},
+ {"Ṕ", 0},
+ {"M", 1},
+ {"Ḿ", 0},
+ {"O", 1},
+ {"Ó", 0},
+ {"abreve", 1},
+ {"ắ", 0},
+ {"m", 1},
+ {"ḿ", 0},
+ {"r", 1},
+ {"ŕ", 0},
+ {"s", 1},
+ {"ś", 0},
+ {"Z", 1},
+ {"Ź", 0},
+ {"macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"A", 1},
+ {"Á", 0},
+ {"R", 1},
+ {"Ŕ", 0},
+ {"c", 1},
+ {"ć", 0},
+ {"Idiaeresis", 1},
+ {"Ḯ", 0},
+ {"L", 1},
+ {"Ĺ", 0},
+ {"Greek_EPSILON", 1},
+ {"Έ", 0},
+ {"Cyrillic_A", 1},
+ {"А́", 0},
+ {"comma", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"asciitilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"Ccedilla", 1},
+ {"Ḉ", 0},
+ {"slash", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"aring", 1},
+ {"ǻ", 0},
+ {"K", 1},
+ {"Ḱ", 0},
+ {"Omacron", 1},
+ {"Ṓ", 0},
+ {"Cyrillic_IE", 1},
+ {"Е́", 0},
+ {"dead_cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"Greek_omega", 1},
+ {"ώ", 0},
+ {"dead_diaeresis", 12},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"Uhorn", 1},
+ {"Ứ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ώ", 0},
+ {"oslash", 1},
+ {"ǿ", 0},
+ {"Cyrillic_ghe", 1},
+ {"ѓ", 0},
+ {"parenleft", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"udiaeresis", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Í", 0},
+ {"N", 1},
+ {"Ń", 0},
+ {"U", 1},
+ {"Ú", 0},
+ {"Cyrillic_u", 1},
+ {"у́", 0},
+ {"ae", 1},
+ {"ǽ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ύ", 0},
+ {"Cyrillic_pe", 2},
+ {"Cyrillic_a", 1},
+ {"§", 0},
+ {"w", 2},
+ {"asciicircum", 1},
+ {"ŵ", 0},
+ {"Greek_ETA", 2},
+ {"apostrophe", 1},
+ {"Ή", 0},
+ {"4", 2},
+ {"5", 1},
+ {"⅘", 0},
+ {"bracketright", 2},
+ {"bracketleft", 1},
+ {"⌷", 0},
+ {"colon", 6},
+ {"minus", 1},
+ {"÷", 0},
+ {"parenright", 1},
+ {"☺", 0},
+ {"parenleft", 1},
+ {"☹", 0},
+ {"p", 4},
+ {"period", 1},
+ {"ṗ", 0},
+ {"exclam", 1},
+ {"¶", 0},
+ {"underscore", 230},
+ {"adiaeresis", 1},
+ {"ǟ", 0},
+ {"period", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"g", 1},
+ {"ḡ", 0},
+ {"a", 1},
+ {"ā", 0},
+ {"Greek_IOTA", 1},
+ {"Ῑ", 0},
+ {"Greek_iota", 1},
+ {"ῑ", 0},
+ {"1", 1},
+ {"₁", 0},
+ {"exclam", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"KP_4", 1},
+ {"₄", 0},
+ {"less", 1},
+ {"≤", 0},
+ {"Cyrillic_er", 1},
+ {"р̄", 0},
+ {"o", 1},
+ {"ō", 0},
+ {"e", 1},
+ {"ē", 0},
+ {"KP_6", 1},
+ {"₆", 0},
+ {"Udiaeresis", 1},
+ {"Ǖ", 0},
+ {"Greek_upsilon", 1},
+ {"ῡ", 0},
+ {"dead_belowdot", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"KP_8", 1},
+ {"₈", 0},
+ {"Cyrillic_I", 1},
+ {"Ӣ", 0},
+ {"y", 1},
+ {"ȳ", 0},
+ {"Cyrillic_O", 1},
+ {"О̄", 0},
+ {"i", 1},
+ {"ī", 0},
+ {"KP_9", 1},
+ {"₉", 0},
+ {"equal", 1},
+ {"₌", 0},
+ {"KP_Space", 1},
+ {"₂", 0},
+ {"dead_tilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"7", 1},
+ {"₇", 0},
+ {"Cyrillic_a", 1},
+ {"а̄", 0},
+ {"parenright", 1},
+ {"₎", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̄", 0},
+ {"KP_7", 1},
+ {"₇", 0},
+ {"Cyrillic_U", 1},
+ {"Ӯ", 0},
+ {"AE", 1},
+ {"Ǣ", 0},
+ {"u", 1},
+ {"ū", 0},
+ {"G", 1},
+ {"Ḡ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾱ", 0},
+ {"otilde", 1},
+ {"ȭ", 0},
+ {"8", 1},
+ {"₈", 0},
+ {"KP_1", 1},
+ {"₁", 0},
+ {"3", 1},
+ {"₃", 0},
+ {"Cyrillic_ie", 1},
+ {"е̄", 0},
+ {"E", 1},
+ {"Ē", 0},
+ {"2", 1},
+ {"₂", 0},
+ {"Y", 1},
+ {"Ȳ", 0},
+ {"Cyrillic_i", 1},
+ {"ӣ", 0},
+ {"dead_ogonek", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"odiaeresis", 1},
+ {"ȫ", 0},
+ {"Otilde", 1},
+ {"Ȭ", 0},
+ {"quotedbl", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"plus", 1},
+ {"₊", 0},
+ {"6", 1},
+ {"₆", 0},
+ {"Greek_alpha", 1},
+ {"ᾱ", 0},
+ {"dead_abovedot", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"Cyrillic_o", 1},
+ {"о̄", 0},
+ {"4", 1},
+ {"₄", 0},
+ {"KP_3", 1},
+ {"₃", 0},
+ {"underscore", 1},
+ {"¯", 0},
+ {"apostrophe", 1},
+ {"⍘", 0},
+ {"O", 1},
+ {"Ō", 0},
+ {"KP_0", 1},
+ {"₀", 0},
+ {"A", 1},
+ {"Ā", 0},
+ {"KP_Add", 1},
+ {"₊", 0},
+ {"Odiaeresis", 1},
+ {"Ȫ", 0},
+ {"KP_2", 1},
+ {"₂", 0},
+ {"Cyrillic_A", 1},
+ {"А̄", 0},
+ {"asciitilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"5", 1},
+ {"₅", 0},
+ {"greater", 1},
+ {"≥", 0},
+ {"semicolon", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"KP_5", 1},
+ {"₅", 0},
+ {"9", 1},
+ {"₉", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̄", 0},
+ {"0", 1},
+ {"₀", 0},
+ {"dead_diaeresis", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"Adiaeresis", 1},
+ {"Ǟ", 0},
+ {"parenleft", 1},
+ {"₍", 0},
+ {"udiaeresis", 1},
+ {"ǖ", 0},
+ {"I", 1},
+ {"Ī", 0},
+ {"U", 1},
+ {"Ū", 0},
+ {"Cyrillic_u", 1},
+ {"ӯ", 0},
+ {"ae", 1},
+ {"ǣ", 0},
+ {"asciicircum", 1},
+ {"¯", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῡ", 0},
+ {"KP_Equal", 1},
+ {"₌", 0},
+ {"v", 8},
+ {"l", 1},
+ {"|", 0},
+ {"z", 1},
+ {"ž", 0},
+ {"Z", 1},
+ {"Ž", 0},
+ {"slash", 1},
+ {"√", 0},
+ {"P", 8},
+ {"period", 1},
+ {"Ṗ", 0},
+ {"exclam", 1},
+ {"¶", 0},
+ {"t", 1},
+ {"₧", 0},
+ {"P", 1},
+ {"¶", 0},
+ {"question", 106},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"a", 1},
+ {"ả", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ẩ", 0},
+ {"e", 1},
+ {"ể", 0},
+ {"o", 1},
+ {"ổ", 0},
+ {"E", 1},
+ {"Ể", 0},
+ {"O", 1},
+ {"Ổ", 0},
+ {"A", 1},
+ {"Ẩ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ở", 0},
+ {"u", 1},
+ {"ử", 0},
+ {"O", 1},
+ {"Ở", 0},
+ {"U", 1},
+ {"Ử", 0},
+ {"Acircumflex", 1},
+ {"Ẩ", 0},
+ {"exclam", 1},
+ {"⸘", 0},
+ {"e", 1},
+ {"ẻ", 0},
+ {"o", 1},
+ {"ỏ", 0},
+ {"uhorn", 1},
+ {"ử", 0},
+ {"acircumflex", 1},
+ {"ẩ", 0},
+ {"Ecircumflex", 1},
+ {"Ể", 0},
+ {"y", 1},
+ {"ỷ", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"i", 1},
+ {"ỉ", 0},
+ {"Ohorn", 1},
+ {"Ở", 0},
+ {"ohorn", 1},
+ {"ở", 0},
+ {"Ocircumflex", 1},
+ {"Ổ", 0},
+ {"ocircumflex", 1},
+ {"ổ", 0},
+ {"u", 1},
+ {"ủ", 0},
+ {"E", 1},
+ {"Ẻ", 0},
+ {"Y", 1},
+ {"Ỷ", 0},
+ {"Abreve", 1},
+ {"Ẳ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ở", 0},
+ {"u", 1},
+ {"ử", 0},
+ {"O", 1},
+ {"Ở", 0},
+ {"U", 1},
+ {"Ử", 0},
+ {"ecircumflex", 1},
+ {"ể", 0},
+ {"question", 1},
+ {"¿", 0},
+ {"O", 1},
+ {"Ỏ", 0},
+ {"abreve", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ả", 0},
+ {"Uhorn", 1},
+ {"Ử", 0},
+ {"I", 1},
+ {"Ỉ", 0},
+ {"U", 1},
+ {"Ủ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ẩ", 0},
+ {"e", 1},
+ {"ể", 0},
+ {"o", 1},
+ {"ổ", 0},
+ {"E", 1},
+ {"Ể", 0},
+ {"O", 1},
+ {"Ổ", 0},
+ {"A", 1},
+ {"Ẩ", 0},
+ {"apostrophe", 470},
+ {"W", 1},
+ {"Ẃ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"g", 1},
+ {"ǵ", 0},
+ {"a", 1},
+ {"á", 0},
+ {"Greek_IOTA", 1},
+ {"Ί", 0},
+ {"Greek_iota", 1},
+ {"ί", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ό", 0},
+ {"Acircumflex", 1},
+ {"Ấ", 0},
+ {"C", 1},
+ {"Ć", 0},
+ {"less", 1},
+ {"‘", 0},
+ {"Cyrillic_er", 1},
+ {"р́", 0},
+ {"e", 1},
+ {"é", 0},
+ {"KP_Divide", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"Utilde", 1},
+ {"Ṹ", 0},
+ {"o", 1},
+ {"ó", 0},
+ {"l", 1},
+ {"ĺ", 0},
+ {"Udiaeresis", 1},
+ {"Ǘ", 0},
+ {"Greek_upsilon", 1},
+ {"ύ", 0},
+ {"uhorn", 1},
+ {"ứ", 0},
+ {"space", 1},
+ {"'", 0},
+ {"dead_macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"acircumflex", 1},
+ {"ấ", 0},
+ {"Ecircumflex", 1},
+ {"Ế", 0},
+ {"Cyrillic_I", 1},
+ {"И́", 0},
+ {"y", 1},
+ {"ý", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"idiaeresis", 1},
+ {"ḯ", 0},
+ {"Cyrillic_O", 1},
+ {"О́", 0},
+ {"i", 1},
+ {"í", 0},
+ {"k", 1},
+ {"ḱ", 0},
+ {"n", 1},
+ {"ń", 0},
+ {"ccedilla", 1},
+ {"ḉ", 0},
+ {"Cyrillic_GHE", 1},
+ {"Ѓ", 0},
+ {"dead_tilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"Cyrillic_a", 1},
+ {"а́", 0},
+ {"parenright", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"Ohorn", 1},
+ {"Ớ", 0},
+ {"ohorn", 1},
+ {"ớ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р́", 0},
+ {"Greek_epsilon", 1},
+ {"έ", 0},
+ {"Cyrillic_KA", 1},
+ {"Ќ", 0},
+ {"Cyrillic_U", 1},
+ {"У́", 0},
+ {"dead_abovering", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"Ocircumflex", 1},
+ {"Ố", 0},
+ {"AE", 1},
+ {"Ǽ", 0},
+ {"omacron", 1},
+ {"ṓ", 0},
+ {"ocircumflex", 1},
+ {"ố", 0},
+ {"u", 1},
+ {"ú", 0},
+ {"z", 1},
+ {"ź", 0},
+ {"G", 1},
+ {"Ǵ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ά", 0},
+ {"otilde", 1},
+ {"ṍ", 0},
+ {"utilde", 1},
+ {"ṹ", 0},
+ {"Cyrillic_ie", 1},
+ {"е́", 0},
+ {"emacron", 1},
+ {"ḗ", 0},
+ {"E", 1},
+ {"É", 0},
+ {"S", 1},
+ {"Ś", 0},
+ {"Greek_iotadieresis", 1},
+ {"ΐ", 0},
+ {"Y", 1},
+ {"Ý", 0},
+ {"Cyrillic_i", 1},
+ {"и́", 0},
+ {"dead_dasia", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ΰ", 0},
+ {"Greek_omicron", 1},
+ {"ό", 0},
+ {"Greek_eta", 1},
+ {"ή", 0},
+ {"Otilde", 1},
+ {"Ṍ", 0},
+ {"Cyrillic_ka", 1},
+ {"ќ", 0},
+ {"Aring", 1},
+ {"Ǻ", 0},
+ {"Abreve", 1},
+ {"Ắ", 0},
+ {"dead_psili", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"quotedbl", 14},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"space", 1},
+ {"΅", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"Greek_alpha", 1},
+ {"ά", 0},
+ {"ecircumflex", 1},
+ {"ế", 0},
+ {"w", 1},
+ {"ẃ", 0},
+ {"Greek_ETA", 1},
+ {"Ή", 0},
+ {"Cyrillic_o", 1},
+ {"о́", 0},
+ {"Emacron", 1},
+ {"Ḗ", 0},
+ {"Ooblique", 1},
+ {"Ǿ", 0},
+ {"p", 1},
+ {"ṕ", 0},
+ {"underscore", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"P", 1},
+ {"Ṕ", 0},
+ {"apostrophe", 1},
+ {"´", 0},
+ {"M", 1},
+ {"Ḿ", 0},
+ {"O", 1},
+ {"Ó", 0},
+ {"abreve", 1},
+ {"ắ", 0},
+ {"m", 1},
+ {"ḿ", 0},
+ {"r", 1},
+ {"ŕ", 0},
+ {"s", 1},
+ {"ś", 0},
+ {"Z", 1},
+ {"Ź", 0},
+ {"macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"A", 1},
+ {"Á", 0},
+ {"R", 1},
+ {"Ŕ", 0},
+ {"c", 1},
+ {"ć", 0},
+ {"Idiaeresis", 1},
+ {"Ḯ", 0},
+ {"L", 1},
+ {"Ĺ", 0},
+ {"Greek_EPSILON", 1},
+ {"Έ", 0},
+ {"Cyrillic_A", 1},
+ {"А́", 0},
+ {"comma", 1},
+ {"‚", 0},
+ {"asciitilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"Ccedilla", 1},
+ {"Ḉ", 0},
+ {"slash", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"aring", 1},
+ {"ǻ", 0},
+ {"greater", 1},
+ {"’", 0},
+ {"K", 1},
+ {"Ḱ", 0},
+ {"Omacron", 1},
+ {"Ṓ", 0},
+ {"Cyrillic_IE", 1},
+ {"Е́", 0},
+ {"dead_cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"Greek_omega", 1},
+ {"ώ", 0},
+ {"dead_diaeresis", 12},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"Uhorn", 1},
+ {"Ứ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ώ", 0},
+ {"oslash", 1},
+ {"ǿ", 0},
+ {"Cyrillic_ghe", 1},
+ {"ѓ", 0},
+ {"parenleft", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"udiaeresis", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Í", 0},
+ {"N", 1},
+ {"Ń", 0},
+ {"U", 1},
+ {"Ú", 0},
+ {"Cyrillic_u", 1},
+ {"у́", 0},
+ {"ae", 1},
+ {"ǽ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ύ", 0},
+ {"M", 2},
+ {"period", 1},
+ {"Ṁ", 0},
+ {"O", 40},
+ {"minus", 1},
+ {"Ō", 0},
+ {"C", 1},
+ {"©", 0},
+ {"diaeresis", 1},
+ {"Ö", 0},
+ {"x", 1},
+ {"¤", 0},
+ {"E", 1},
+ {"Œ", 0},
+ {"S", 1},
+ {"§", 0},
+ {"quotedbl", 1},
+ {"Ö", 0},
+ {"acute", 1},
+ {"Ó", 0},
+ {"underscore", 1},
+ {"Ō", 0},
+ {"apostrophe", 1},
+ {"Ó", 0},
+ {"r", 1},
+ {"®", 0},
+ {"A", 1},
+ {"Ⓐ", 0},
+ {"R", 1},
+ {"®", 0},
+ {"c", 1},
+ {"©", 0},
+ {"asciitilde", 1},
+ {"Õ", 0},
+ {"slash", 1},
+ {"Ø", 0},
+ {"greater", 1},
+ {"Ô", 0},
+ {"X", 1},
+ {"¤", 0},
+ {"grave", 1},
+ {"Ò", 0},
+ {"asciicircum", 1},
+ {"Ô", 0},
+ {"m", 6},
+ {"period", 1},
+ {"ṁ", 0},
+ {"u", 1},
+ {"µ", 0},
+ {"slash", 1},
+ {"₥", 0},
+ {"r", 6},
+ {"less", 1},
+ {"ř", 0},
+ {"apostrophe", 1},
+ {"ŕ", 0},
+ {"comma", 1},
+ {"ŗ", 0},
+ {"s", 20},
+ {"period", 1},
+ {"ṡ", 0},
+ {"exclam", 1},
+ {"§", 0},
+ {"less", 1},
+ {"š", 0},
+ {"o", 1},
+ {"§", 0},
+ {"cedilla", 1},
+ {"ş", 0},
+ {"apostrophe", 1},
+ {"ś", 0},
+ {"M", 1},
+ {"℠", 0},
+ {"m", 1},
+ {"℠", 0},
+ {"s", 1},
+ {"ß", 0},
+ {"comma", 1},
+ {"ş", 0},
+ {"asterisk", 17},
+ {"a", 1},
+ {"å", 0},
+ {"diaeresis", 1},
+ {"⍣", 0},
+ {"u", 1},
+ {"ů", 0},
+ {"apostrophe", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"A", 1},
+ {"Å", 0},
+ {"0", 1},
+ {"°", 0},
+ {"U", 1},
+ {"Ů", 0},
+ {"Z", 6},
+ {"period", 1},
+ {"Ż", 0},
+ {"less", 1},
+ {"Ž", 0},
+ {"apostrophe", 1},
+ {"Ź", 0},
+ {"bar", 6},
+ {"C", 1},
+ {"¢", 0},
+ {"c", 1},
+ {"¢", 0},
+ {"asciitilde", 1},
+ {"⍭", 0},
+ {"macron", 166},
+ {"adiaeresis", 1},
+ {"ǟ", 0},
+ {"period", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"g", 1},
+ {"ḡ", 0},
+ {"a", 1},
+ {"ā", 0},
+ {"Greek_IOTA", 1},
+ {"Ῑ", 0},
+ {"Greek_iota", 1},
+ {"ῑ", 0},
+ {"exclam", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"Cyrillic_er", 1},
+ {"р̄", 0},
+ {"e", 1},
+ {"ē", 0},
+ {"o", 1},
+ {"ō", 0},
+ {"Udiaeresis", 1},
+ {"Ǖ", 0},
+ {"Greek_upsilon", 1},
+ {"ῡ", 0},
+ {"dead_belowdot", 8},
+ {"l", 1},
+ {"ḹ", 0},
+ {"r", 1},
+ {"ṝ", 0},
+ {"R", 1},
+ {"Ṝ", 0},
+ {"L", 1},
+ {"Ḹ", 0},
+ {"Cyrillic_I", 1},
+ {"Ӣ", 0},
+ {"y", 1},
+ {"ȳ", 0},
+ {"Cyrillic_O", 1},
+ {"О̄", 0},
+ {"i", 1},
+ {"ī", 0},
+ {"dead_tilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"Cyrillic_a", 1},
+ {"а̄", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̄", 0},
+ {"Cyrillic_U", 1},
+ {"Ӯ", 0},
+ {"AE", 1},
+ {"Ǣ", 0},
+ {"u", 1},
+ {"ū", 0},
+ {"G", 1},
+ {"Ḡ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾱ", 0},
+ {"otilde", 1},
+ {"ȭ", 0},
+ {"Cyrillic_ie", 1},
+ {"е̄", 0},
+ {"E", 1},
+ {"Ē", 0},
+ {"Y", 1},
+ {"Ȳ", 0},
+ {"Cyrillic_i", 1},
+ {"ӣ", 0},
+ {"dead_ogonek", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"odiaeresis", 1},
+ {"ȫ", 0},
+ {"Otilde", 1},
+ {"Ȭ", 0},
+ {"quotedbl", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾱ", 0},
+ {"dead_abovedot", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"Cyrillic_o", 1},
+ {"о̄", 0},
+ {"O", 1},
+ {"Ō", 0},
+ {"A", 1},
+ {"Ā", 0},
+ {"Odiaeresis", 1},
+ {"Ȫ", 0},
+ {"Cyrillic_A", 1},
+ {"А̄", 0},
+ {"asciitilde", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"semicolon", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̄", 0},
+ {"dead_diaeresis", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ǖ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ǖ", 0},
+ {"Adiaeresis", 1},
+ {"Ǟ", 0},
+ {"udiaeresis", 1},
+ {"ǖ", 0},
+ {"I", 1},
+ {"Ī", 0},
+ {"U", 1},
+ {"Ū", 0},
+ {"Cyrillic_u", 1},
+ {"ӯ", 0},
+ {"ae", 1},
+ {"ǣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῡ", 0},
+ {"A", 32},
+ {"minus", 1},
+ {"Ā", 0},
+ {"diaeresis", 1},
+ {"Ä", 0},
+ {"E", 1},
+ {"Æ", 0},
+ {"quotedbl", 1},
+ {"Ä", 0},
+ {"acute", 1},
+ {"Á", 0},
+ {"underscore", 1},
+ {"Ā", 0},
+ {"apostrophe", 1},
+ {"Á", 0},
+ {"asterisk", 1},
+ {"Å", 0},
+ {"A", 1},
+ {"Å", 0},
+ {"comma", 1},
+ {"Ą", 0},
+ {"T", 1},
+ {"@", 0},
+ {"asciitilde", 1},
+ {"Ã", 0},
+ {"greater", 1},
+ {"Â", 0},
+ {"parenleft", 1},
+ {"Ă", 0},
+ {"grave", 1},
+ {"À", 0},
+ {"asciicircum", 1},
+ {"Â", 0},
+ {"R", 10},
+ {"less", 1},
+ {"Ř", 0},
+ {"apostrophe", 1},
+ {"Ŕ", 0},
+ {"O", 1},
+ {"®", 0},
+ {"s", 1},
+ {"₨", 0},
+ {"comma", 1},
+ {"Ŗ", 0},
+ {"Cyrillic_ES", 2},
+ {"equal", 1},
+ {"€", 0},
+ {"c", 98},
+ {"period", 1},
+ {"ċ", 0},
+ {"g", 1},
+ {"ǧ", 0},
+ {"a", 1},
+ {"ǎ", 0},
+ {"ezh", 1},
+ {"ǯ", 0},
+ {"C", 1},
+ {"Č", 0},
+ {"less", 1},
+ {"č", 0},
+ {"e", 1},
+ {"ě", 0},
+ {"o", 1},
+ {"ǒ", 0},
+ {"l", 1},
+ {"ľ", 0},
+ {"Udiaeresis", 1},
+ {"Ǚ", 0},
+ {"t", 1},
+ {"ť", 0},
+ {"i", 1},
+ {"ǐ", 0},
+ {"k", 1},
+ {"ǩ", 0},
+ {"n", 1},
+ {"ň", 0},
+ {"equal", 1},
+ {"€", 0},
+ {"j", 1},
+ {"ǰ", 0},
+ {"u", 1},
+ {"ǔ", 0},
+ {"z", 1},
+ {"ž", 0},
+ {"G", 1},
+ {"Ǧ", 0},
+ {"H", 1},
+ {"Ȟ", 0},
+ {"E", 1},
+ {"Ě", 0},
+ {"S", 1},
+ {"Š", 0},
+ {"d", 1},
+ {"ď", 0},
+ {"D", 1},
+ {"Ď", 0},
+ {"quotedbl", 4},
+ {"u", 1},
+ {"ǚ", 0},
+ {"U", 1},
+ {"Ǚ", 0},
+ {"apostrophe", 1},
+ {"ć", 0},
+ {"O", 1},
+ {"Ǒ", 0},
+ {"r", 1},
+ {"ř", 0},
+ {"s", 1},
+ {"š", 0},
+ {"Z", 1},
+ {"Ž", 0},
+ {"bar", 1},
+ {"¢", 0},
+ {"EZH", 1},
+ {"Ǯ", 0},
+ {"A", 1},
+ {"Ǎ", 0},
+ {"R", 1},
+ {"Ř", 0},
+ {"c", 1},
+ {"č", 0},
+ {"L", 1},
+ {"Ľ", 0},
+ {"comma", 1},
+ {"ç", 0},
+ {"T", 1},
+ {"Ť", 0},
+ {"slash", 1},
+ {"¢", 0},
+ {"K", 1},
+ {"Ǩ", 0},
+ {"dead_diaeresis", 4},
+ {"u", 1},
+ {"ǚ", 0},
+ {"U", 1},
+ {"Ǚ", 0},
+ {"h", 1},
+ {"ȟ", 0},
+ {"udiaeresis", 1},
+ {"ǚ", 0},
+ {"I", 1},
+ {"Ǐ", 0},
+ {"N", 1},
+ {"Ň", 0},
+ {"U", 1},
+ {"Ǔ", 0},
+ {"numbersign", 14},
+ {"e", 1},
+ {"♪", 0},
+ {"b", 1},
+ {"♭", 0},
+ {"q", 1},
+ {"♩", 0},
+ {"E", 1},
+ {"♫", 0},
+ {"S", 1},
+ {"♬", 0},
+ {"f", 1},
+ {"♮", 0},
+ {"numbersign", 1},
+ {"♯", 0},
+ {"L", 14},
+ {"minus", 1},
+ {"£", 0},
+ {"less", 1},
+ {"Ľ", 0},
+ {"equal", 1},
+ {"₤", 0},
+ {"V", 1},
+ {"|", 0},
+ {"apostrophe", 1},
+ {"Ĺ", 0},
+ {"comma", 1},
+ {"Ļ", 0},
+ {"slash", 1},
+ {"Ł", 0},
+ {"Greek_EPSILON", 2},
+ {"apostrophe", 1},
+ {"Έ", 0},
+ {"comma", 66},
+ {"minus", 1},
+ {"¬", 0},
+ {"g", 1},
+ {"ģ", 0},
+ {"a", 1},
+ {"ą", 0},
+ {"C", 1},
+ {"Ç", 0},
+ {"e", 1},
+ {"ę", 0},
+ {"l", 1},
+ {"ļ", 0},
+ {"t", 1},
+ {"ţ", 0},
+ {"space", 1},
+ {"¸", 0},
+ {"i", 1},
+ {"į", 0},
+ {"k", 1},
+ {"ķ", 0},
+ {"n", 1},
+ {"ņ", 0},
+ {"u", 1},
+ {"ų", 0},
+ {"G", 1},
+ {"Ģ", 0},
+ {"H", 1},
+ {"Ḩ", 0},
+ {"E", 1},
+ {"Ę", 0},
+ {"S", 1},
+ {"Ş", 0},
+ {"d", 1},
+ {"ḑ", 0},
+ {"D", 1},
+ {"Ḑ", 0},
+ {"quotedbl", 1},
+ {"„", 0},
+ {"apostrophe", 1},
+ {"‚", 0},
+ {"r", 1},
+ {"ŗ", 0},
+ {"s", 1},
+ {"ş", 0},
+ {"A", 1},
+ {"Ą", 0},
+ {"R", 1},
+ {"Ŗ", 0},
+ {"c", 1},
+ {"ç", 0},
+ {"L", 1},
+ {"Ļ", 0},
+ {"comma", 1},
+ {"¸", 0},
+ {"T", 1},
+ {"Ţ", 0},
+ {"K", 1},
+ {"Ķ", 0},
+ {"h", 1},
+ {"ḩ", 0},
+ {"I", 1},
+ {"Į", 0},
+ {"N", 1},
+ {"Ņ", 0},
+ {"U", 1},
+ {"Ų", 0},
+ {"T", 16},
+ {"minus", 1},
+ {"Ŧ", 0},
+ {"period", 1},
+ {"Ṫ", 0},
+ {"less", 1},
+ {"Ť", 0},
+ {"H", 1},
+ {"Þ", 0},
+ {"M", 1},
+ {"™", 0},
+ {"m", 1},
+ {"™", 0},
+ {"comma", 1},
+ {"Ţ", 0},
+ {"slash", 1},
+ {"Ŧ", 0},
+ {"asciitilde", 222},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"a", 1},
+ {"ã", 0},
+ {"Greek_iota", 1},
+ {"ῖ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ỡ", 0},
+ {"u", 1},
+ {"ữ", 0},
+ {"O", 1},
+ {"Ỡ", 0},
+ {"U", 1},
+ {"Ữ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ẫ", 0},
+ {"e", 1},
+ {"ễ", 0},
+ {"o", 1},
+ {"ỗ", 0},
+ {"E", 1},
+ {"Ễ", 0},
+ {"O", 1},
+ {"Ỗ", 0},
+ {"A", 1},
+ {"Ẫ", 0},
+ {"Acircumflex", 1},
+ {"Ẫ", 0},
+ {"e", 1},
+ {"ẽ", 0},
+ {"o", 1},
+ {"õ", 0},
+ {"Greek_upsilon", 1},
+ {"ῦ", 0},
+ {"diaeresis", 1},
+ {"⍨", 0},
+ {"uhorn", 1},
+ {"ữ", 0},
+ {"space", 1},
+ {"~", 0},
+ {"acircumflex", 1},
+ {"ẫ", 0},
+ {"Ecircumflex", 1},
+ {"Ễ", 0},
+ {"y", 1},
+ {"ỹ", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"i", 1},
+ {"ĩ", 0},
+ {"n", 1},
+ {"ñ", 0},
+ {"parenright", 18},
+ {"Greek_IOTA", 1},
+ {"Ἶ", 0},
+ {"Greek_iota", 1},
+ {"ἶ", 0},
+ {"Greek_upsilon", 1},
+ {"ὖ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἆ", 0},
+ {"Greek_eta", 1},
+ {"ἦ", 0},
+ {"Greek_alpha", 1},
+ {"ἆ", 0},
+ {"Greek_ETA", 1},
+ {"Ἦ", 0},
+ {"Greek_omega", 1},
+ {"ὦ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὦ", 0},
+ {"Ohorn", 1},
+ {"Ỡ", 0},
+ {"ohorn", 1},
+ {"ỡ", 0},
+ {"Ocircumflex", 1},
+ {"Ỗ", 0},
+ {"V", 1},
+ {"Ṽ", 0},
+ {"ocircumflex", 1},
+ {"ỗ", 0},
+ {"u", 1},
+ {"ũ", 0},
+ {"E", 1},
+ {"Ẽ", 0},
+ {"Greek_iotadieresis", 1},
+ {"ῗ", 0},
+ {"Y", 1},
+ {"Ỹ", 0},
+ {"dead_dasia", 20},
+ {"Greek_IOTA", 1},
+ {"Ἷ", 0},
+ {"Greek_iota", 1},
+ {"ἷ", 0},
+ {"Greek_upsilon", 1},
+ {"ὗ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἇ", 0},
+ {"Greek_eta", 1},
+ {"ἧ", 0},
+ {"Greek_alpha", 1},
+ {"ἇ", 0},
+ {"Greek_ETA", 1},
+ {"Ἧ", 0},
+ {"Greek_omega", 1},
+ {"ὧ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὧ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὗ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ῧ", 0},
+ {"Greek_eta", 1},
+ {"ῆ", 0},
+ {"Abreve", 1},
+ {"Ẵ", 0},
+ {"dead_psili", 18},
+ {"Greek_IOTA", 1},
+ {"Ἶ", 0},
+ {"Greek_iota", 1},
+ {"ἶ", 0},
+ {"Greek_upsilon", 1},
+ {"ὖ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἆ", 0},
+ {"Greek_eta", 1},
+ {"ἦ", 0},
+ {"Greek_alpha", 1},
+ {"ἆ", 0},
+ {"Greek_ETA", 1},
+ {"Ἦ", 0},
+ {"Greek_omega", 1},
+ {"ὦ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὦ", 0},
+ {"quotedbl", 4},
+ {"Greek_iota", 1},
+ {"ῗ", 0},
+ {"Greek_upsilon", 1},
+ {"ῧ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ỡ", 0},
+ {"u", 1},
+ {"ữ", 0},
+ {"O", 1},
+ {"Ỡ", 0},
+ {"U", 1},
+ {"Ữ", 0},
+ {"Greek_alpha", 1},
+ {"ᾶ", 0},
+ {"ecircumflex", 1},
+ {"ễ", 0},
+ {"v", 1},
+ {"ṽ", 0},
+ {"O", 1},
+ {"Õ", 0},
+ {"abreve", 1},
+ {"ẵ", 0},
+ {"bar", 1},
+ {"⍭", 0},
+ {"A", 1},
+ {"Ã", 0},
+ {"0", 1},
+ {"⍬", 0},
+ {"Greek_omega", 1},
+ {"ῶ", 0},
+ {"dead_diaeresis", 4},
+ {"Greek_iota", 1},
+ {"ῗ", 0},
+ {"Greek_upsilon", 1},
+ {"ῧ", 0},
+ {"Uhorn", 1},
+ {"Ữ", 0},
+ {"parenleft", 20},
+ {"Greek_IOTA", 1},
+ {"Ἷ", 0},
+ {"Greek_iota", 1},
+ {"ἷ", 0},
+ {"Greek_upsilon", 1},
+ {"ὗ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἇ", 0},
+ {"Greek_eta", 1},
+ {"ἧ", 0},
+ {"Greek_alpha", 1},
+ {"ἇ", 0},
+ {"Greek_ETA", 1},
+ {"Ἧ", 0},
+ {"Greek_omega", 1},
+ {"ὧ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὧ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὗ", 0},
+ {"I", 1},
+ {"Ĩ", 0},
+ {"N", 1},
+ {"Ñ", 0},
+ {"U", 1},
+ {"Ũ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ẫ", 0},
+ {"e", 1},
+ {"ễ", 0},
+ {"o", 1},
+ {"ỗ", 0},
+ {"E", 1},
+ {"Ễ", 0},
+ {"O", 1},
+ {"Ỗ", 0},
+ {"A", 1},
+ {"Ẫ", 0},
+ {"slash", 66},
+ {"minus", 1},
+ {"⌿", 0},
+ {"g", 1},
+ {"ǥ", 0},
+ {"C", 1},
+ {"₡", 0},
+ {"less", 1},
+ {"\\", 0},
+ {"o", 1},
+ {"ø", 0},
+ {"l", 1},
+ {"ł", 0},
+ {"t", 1},
+ {"ŧ", 0},
+ {"b", 1},
+ {"ƀ", 0},
+ {"i", 1},
+ {"ɨ", 0},
+ {"equal", 1},
+ {"≠", 0},
+ {"Cyrillic_GHE", 1},
+ {"Ғ", 0},
+ {"leftarrow", 1},
+ {"↚", 0},
+ {"Cyrillic_KA", 1},
+ {"Ҟ", 0},
+ {"u", 1},
+ {"µ", 0},
+ {"rightarrow", 1},
+ {"↛", 0},
+ {"z", 1},
+ {"ƶ", 0},
+ {"G", 1},
+ {"Ǥ", 0},
+ {"H", 1},
+ {"Ħ", 0},
+ {"d", 1},
+ {"đ", 0},
+ {"Cyrillic_ka", 1},
+ {"ҟ", 0},
+ {"D", 1},
+ {"Đ", 0},
+ {"v", 1},
+ {"√", 0},
+ {"O", 1},
+ {"Ø", 0},
+ {"m", 1},
+ {"₥", 0},
+ {"Z", 1},
+ {"Ƶ", 0},
+ {"c", 1},
+ {"¢", 0},
+ {"L", 1},
+ {"Ł", 0},
+ {"T", 1},
+ {"Ŧ", 0},
+ {"slash", 1},
+ {"\\", 0},
+ {"Cyrillic_ghe", 1},
+ {"ғ", 0},
+ {"h", 1},
+ {"ħ", 0},
+ {"I", 1},
+ {"Ɨ", 0},
+ {"asciicircum", 1},
+ {"|", 0},
+ {"5", 4},
+ {"8", 1},
+ {"⅝", 0},
+ {"6", 1},
+ {"⅚", 0},
+ {"Cyrillic_EN", 4},
+ {"Cyrillic_O", 1},
+ {"№", 0},
+ {"Cyrillic_o", 1},
+ {"№", 0},
+ {"greater", 36},
+ {"a", 1},
+ {"â", 0},
+ {"less", 1},
+ {"⋄", 0},
+ {"e", 1},
+ {"ê", 0},
+ {"o", 1},
+ {"ô", 0},
+ {"diaeresis", 1},
+ {"⍩", 0},
+ {"space", 1},
+ {"^", 0},
+ {"i", 1},
+ {"î", 0},
+ {"equal", 1},
+ {"≥", 0},
+ {"u", 1},
+ {"û", 0},
+ {"E", 1},
+ {"Ê", 0},
+ {"quotedbl", 1},
+ {"”", 0},
+ {"underscore", 1},
+ {"≥", 0},
+ {"apostrophe", 1},
+ {"’", 0},
+ {"O", 1},
+ {"Ô", 0},
+ {"A", 1},
+ {"Â", 0},
+ {"greater", 1},
+ {"»", 0},
+ {"I", 1},
+ {"Î", 0},
+ {"U", 1},
+ {"Û", 0},
+ {"semicolon", 22},
+ {"a", 1},
+ {"ą", 0},
+ {"e", 1},
+ {"ę", 0},
+ {"o", 1},
+ {"ǫ", 0},
+ {"i", 1},
+ {"į", 0},
+ {"u", 1},
+ {"ų", 0},
+ {"E", 1},
+ {"Ę", 0},
+ {"underscore", 1},
+ {"⍮", 0},
+ {"O", 1},
+ {"Ǫ", 0},
+ {"A", 1},
+ {"Ą", 0},
+ {"I", 1},
+ {"Į", 0},
+ {"U", 1},
+ {"Ų", 0},
+ {"K", 2},
+ {"comma", 1},
+ {"Ķ", 0},
+ {"Cyrillic_IE", 2},
+ {"equal", 1},
+ {"€", 0},
+ {"B", 2},
+ {"period", 1},
+ {"Ḃ", 0},
+ {"0", 6},
+ {"3", 1},
+ {"↉", 0},
+ {"asterisk", 1},
+ {"°", 0},
+ {"asciitilde", 1},
+ {"⍬", 0},
+ {"Greek_omega", 2},
+ {"apostrophe", 1},
+ {"ώ", 0},
+ {"Greek_OMEGA", 2},
+ {"apostrophe", 1},
+ {"Ώ", 0},
+ {"X", 4},
+ {"o", 1},
+ {"¤", 0},
+ {"O", 1},
+ {"¤", 0},
+ {"parenleft", 971},
+ {"minus", 1},
+ {"{", 0},
+ {"W", 2},
+ {"parenright", 1},
+ {"Ⓦ", 0},
+ {"g", 2},
+ {"parenright", 1},
+ {"ⓖ", 0},
+ {"kana_KE", 2},
+ {"parenright", 1},
+ {"㋘", 0},
+ {"a", 2},
+ {"parenright", 1},
+ {"ⓐ", 0},
+ {"Greek_IOTA", 1},
+ {"Ἱ", 0},
+ {"Greek_iota", 1},
+ {"ἱ", 0},
+ {"1", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"⑪", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"⑭", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"⑯", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"⑱", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"⑲", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"⑰", 0},
+ {"parenright", 1},
+ {"①", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"⑰", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"⑱", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"⑪", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"⑬", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"⑯", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"⑭", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"⑬", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⑩", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"⑮", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"⑮", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"⑲", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⑩", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὁ", 0},
+ {"C", 2},
+ {"parenright", 1},
+ {"Ⓒ", 0},
+ {"KP_4", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㊶", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㊹", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㊻", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㊽", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㊾", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㊼", 0},
+ {"parenright", 1},
+ {"④", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㊼", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㊽", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㊶", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㊸", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㊻", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㊹", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㊸", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㊵", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㊺", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㊺", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㊾", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㊵", 0},
+ {"kana_SA", 2},
+ {"parenright", 1},
+ {"㋚", 0},
+ {"e", 2},
+ {"parenright", 1},
+ {"ⓔ", 0},
+ {"F", 2},
+ {"parenright", 1},
+ {"Ⓕ", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"⑥", 0},
+ {"o", 2},
+ {"parenright", 1},
+ {"ⓞ", 0},
+ {"l", 2},
+ {"parenright", 1},
+ {"ⓛ", 0},
+ {"kana_SE", 2},
+ {"parenright", 1},
+ {"㋝", 0},
+ {"kana_SU", 2},
+ {"parenright", 1},
+ {"㋜", 0},
+ {"t", 2},
+ {"parenright", 1},
+ {"ⓣ", 0},
+ {"kana_ME", 2},
+ {"parenright", 1},
+ {"㋱", 0},
+ {"Greek_upsilon", 1},
+ {"ὑ", 0},
+ {"kana_WO", 2},
+ {"parenright", 1},
+ {"㋾", 0},
+ {"space", 1},
+ {"˘", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"⑧", 0},
+ {"Greek_RHO", 1},
+ {"Ῥ", 0},
+ {"Q", 2},
+ {"parenright", 1},
+ {"Ⓠ", 0},
+ {"y", 2},
+ {"parenright", 1},
+ {"ⓨ", 0},
+ {"b", 2},
+ {"parenright", 1},
+ {"ⓑ", 0},
+ {"kana_YO", 2},
+ {"parenright", 1},
+ {"㋵", 0},
+ {"i", 2},
+ {"parenright", 1},
+ {"ⓘ", 0},
+ {"kana_MA", 2},
+ {"parenright", 1},
+ {"㋮", 0},
+ {"k", 2},
+ {"parenright", 1},
+ {"ⓚ", 0},
+ {"n", 2},
+ {"parenright", 1},
+ {"ⓝ", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"⑨", 0},
+ {"KP_Space", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"parenright", 1},
+ {"②", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"kana_YU", 2},
+ {"parenright", 1},
+ {"㋴", 0},
+ {"kana_TE", 2},
+ {"parenright", 1},
+ {"㋢", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"⑦", 0},
+ {"kana_NU", 2},
+ {"parenright", 1},
+ {"㋦", 0},
+ {"kana_HO", 2},
+ {"parenright", 1},
+ {"㋭", 0},
+ {"kana_HI", 2},
+ {"parenright", 1},
+ {"㋪", 0},
+ {"j", 2},
+ {"parenright", 1},
+ {"ⓙ", 0},
+ {"kana_E", 2},
+ {"parenright", 1},
+ {"㋓", 0},
+ {"x", 2},
+ {"parenright", 1},
+ {"ⓧ", 0},
+ {"Greek_epsilon", 1},
+ {"ἑ", 0},
+ {"q", 2},
+ {"parenright", 1},
+ {"ⓠ", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"⑦", 0},
+ {"kana_I", 2},
+ {"parenright", 1},
+ {"㋑", 0},
+ {"kana_WA", 2},
+ {"parenright", 1},
+ {"㋻", 0},
+ {"kana_RU", 2},
+ {"parenright", 1},
+ {"㋸", 0},
+ {"V", 2},
+ {"parenright", 1},
+ {"Ⓥ", 0},
+ {"u", 2},
+ {"parenright", 1},
+ {"ⓤ", 0},
+ {"kana_NI", 2},
+ {"parenright", 1},
+ {"㋥", 0},
+ {"kana_MU", 2},
+ {"parenright", 1},
+ {"㋰", 0},
+ {"kana_CHI", 2},
+ {"parenright", 1},
+ {"㋠", 0},
+ {"kana_HA", 2},
+ {"parenright", 1},
+ {"㋩", 0},
+ {"z", 2},
+ {"parenright", 1},
+ {"ⓩ", 0},
+ {"G", 2},
+ {"parenright", 1},
+ {"Ⓖ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἁ", 0},
+ {"H", 2},
+ {"parenright", 1},
+ {"Ⓗ", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"⑧", 0},
+ {"KP_1", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"⑪", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"⑭", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"⑯", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"⑱", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"⑲", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"⑰", 0},
+ {"parenright", 1},
+ {"①", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"⑰", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"⑱", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"⑪", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"⑬", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"⑯", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"⑭", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"⑬", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⑩", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"⑫", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"⑮", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"⑮", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"⑲", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⑩", 0},
+ {"3", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㉛", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㉞", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㊱", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㊳", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㊴", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㊲", 0},
+ {"parenright", 1},
+ {"③", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㊲", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㊳", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㉛", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㉝", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㊱", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㉞", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㉝", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㉚", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㉟", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㉟", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㊴", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㉚", 0},
+ {"E", 2},
+ {"parenright", 1},
+ {"Ⓔ", 0},
+ {"S", 2},
+ {"parenright", 1},
+ {"Ⓢ", 0},
+ {"2", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"parenright", 1},
+ {"②", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"Y", 2},
+ {"parenright", 1},
+ {"Ⓨ", 0},
+ {"kana_RA", 2},
+ {"parenright", 1},
+ {"㋶", 0},
+ {"f", 2},
+ {"parenright", 1},
+ {"ⓕ", 0},
+ {"Greek_omicron", 1},
+ {"ὁ", 0},
+ {"Greek_eta", 1},
+ {"ἡ", 0},
+ {"kana_HE", 2},
+ {"parenright", 1},
+ {"㋬", 0},
+ {"Greek_rho", 1},
+ {"ῥ", 0},
+ {"kana_KO", 2},
+ {"parenright", 1},
+ {"㋙", 0},
+ {"d", 2},
+ {"parenright", 1},
+ {"ⓓ", 0},
+ {"kana_NE", 2},
+ {"parenright", 1},
+ {"㋧", 0},
+ {"D", 2},
+ {"parenright", 1},
+ {"Ⓓ", 0},
+ {"kana_FU", 2},
+ {"parenright", 1},
+ {"㋫", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"⑥", 0},
+ {"Greek_alpha", 1},
+ {"ἁ", 0},
+ {"kana_A", 2},
+ {"parenright", 1},
+ {"㋐", 0},
+ {"w", 2},
+ {"parenright", 1},
+ {"ⓦ", 0},
+ {"Greek_ETA", 1},
+ {"Ἡ", 0},
+ {"4", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㊶", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㊹", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㊻", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㊽", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㊾", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㊼", 0},
+ {"parenright", 1},
+ {"④", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㊼", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㊽", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㊶", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㊸", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㊻", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㊹", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㊸", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㊵", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㊷", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㊺", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㊺", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㊾", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㊵", 0},
+ {"kana_KU", 2},
+ {"parenright", 1},
+ {"㋗", 0},
+ {"KP_3", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㉛", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㉞", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㊱", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㊳", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㊴", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㊲", 0},
+ {"parenright", 1},
+ {"③", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㊲", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㊳", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㉛", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㉝", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㊱", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㉞", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㉝", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㉚", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㉜", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㉟", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㉟", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㊴", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㉚", 0},
+ {"p", 2},
+ {"parenright", 1},
+ {"ⓟ", 0},
+ {"J", 2},
+ {"parenright", 1},
+ {"Ⓙ", 0},
+ {"kana_YA", 2},
+ {"parenright", 1},
+ {"㋳", 0},
+ {"v", 2},
+ {"parenright", 1},
+ {"ⓥ", 0},
+ {"P", 2},
+ {"parenright", 1},
+ {"Ⓟ", 0},
+ {"M", 2},
+ {"parenright", 1},
+ {"Ⓜ", 0},
+ {"O", 2},
+ {"parenright", 1},
+ {"Ⓞ", 0},
+ {"m", 2},
+ {"parenright", 1},
+ {"ⓜ", 0},
+ {"r", 2},
+ {"parenright", 1},
+ {"ⓡ", 0},
+ {"s", 2},
+ {"parenright", 1},
+ {"ⓢ", 0},
+ {"Z", 2},
+ {"parenright", 1},
+ {"Ⓩ", 0},
+ {"kana_U", 2},
+ {"parenright", 1},
+ {"㋒", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⓪", 0},
+ {"A", 2},
+ {"parenright", 1},
+ {"Ⓐ", 0},
+ {"R", 2},
+ {"parenright", 1},
+ {"Ⓡ", 0},
+ {"kana_TO", 2},
+ {"parenright", 1},
+ {"㋣", 0},
+ {"kana_TA", 2},
+ {"parenright", 1},
+ {"㋟", 0},
+ {"c", 2},
+ {"parenright", 1},
+ {"ⓒ", 0},
+ {"kana_RO", 2},
+ {"parenright", 1},
+ {"㋺", 0},
+ {"L", 2},
+ {"parenright", 1},
+ {"Ⓛ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἑ", 0},
+ {"KP_2", 65},
+ {"1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"KP_4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"KP_8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"KP_Space", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"parenright", 1},
+ {"②", 0},
+ {"KP_7", 2},
+ {"parenright", 1},
+ {"㉗", 0},
+ {"8", 2},
+ {"parenright", 1},
+ {"㉘", 0},
+ {"KP_1", 2},
+ {"parenright", 1},
+ {"㉑", 0},
+ {"3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"6", 2},
+ {"parenright", 1},
+ {"㉖", 0},
+ {"4", 2},
+ {"parenright", 1},
+ {"㉔", 0},
+ {"KP_3", 2},
+ {"parenright", 1},
+ {"㉓", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"KP_2", 2},
+ {"parenright", 1},
+ {"㉒", 0},
+ {"5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"KP_5", 2},
+ {"parenright", 1},
+ {"㉕", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"㉙", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⑳", 0},
+ {"kana_O", 2},
+ {"parenright", 1},
+ {"㋔", 0},
+ {"kana_RI", 2},
+ {"parenright", 1},
+ {"㋷", 0},
+ {"T", 2},
+ {"parenright", 1},
+ {"Ⓣ", 0},
+ {"kana_KA", 2},
+ {"parenright", 1},
+ {"㋕", 0},
+ {"kana_MI", 2},
+ {"parenright", 1},
+ {"㋯", 0},
+ {"5", 8},
+ {"parenright", 1},
+ {"⑤", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㊿", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㊿", 0},
+ {"kana_KI", 2},
+ {"parenright", 1},
+ {"㋖", 0},
+ {"KP_5", 8},
+ {"parenright", 1},
+ {"⑤", 0},
+ {"KP_0", 2},
+ {"parenright", 1},
+ {"㊿", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"㊿", 0},
+ {"K", 2},
+ {"parenright", 1},
+ {"Ⓚ", 0},
+ {"9", 2},
+ {"parenright", 1},
+ {"⑨", 0},
+ {"kana_SO", 2},
+ {"parenright", 1},
+ {"㋞", 0},
+ {"B", 2},
+ {"parenright", 1},
+ {"Ⓑ", 0},
+ {"kana_TSU", 2},
+ {"parenright", 1},
+ {"㋡", 0},
+ {"0", 2},
+ {"parenright", 1},
+ {"⓪", 0},
+ {"kana_MO", 2},
+ {"parenright", 1},
+ {"㋲", 0},
+ {"Greek_omega", 1},
+ {"ὡ", 0},
+ {"kana_NO", 2},
+ {"parenright", 1},
+ {"㋨", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὡ", 0},
+ {"kana_NA", 2},
+ {"parenright", 1},
+ {"㋤", 0},
+ {"X", 2},
+ {"parenright", 1},
+ {"Ⓧ", 0},
+ {"parenleft", 1},
+ {"[", 0},
+ {"h", 2},
+ {"parenright", 1},
+ {"ⓗ", 0},
+ {"I", 2},
+ {"parenright", 1},
+ {"Ⓘ", 0},
+ {"N", 2},
+ {"parenright", 1},
+ {"Ⓝ", 0},
+ {"kana_SHI", 2},
+ {"parenright", 1},
+ {"㋛", 0},
+ {"U", 2},
+ {"parenright", 1},
+ {"Ⓤ", 0},
+ {"kana_RE", 2},
+ {"parenright", 1},
+ {"㋹", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὑ", 0},
+ {"h", 2},
+ {"comma", 1},
+ {"ḩ", 0},
+ {"I", 28},
+ {"minus", 1},
+ {"Ī", 0},
+ {"period", 1},
+ {"İ", 0},
+ {"diaeresis", 1},
+ {"Ï", 0},
+ {"j", 1},
+ {"IJ", 0},
+ {"quotedbl", 1},
+ {"Ï", 0},
+ {"acute", 1},
+ {"Í", 0},
+ {"underscore", 1},
+ {"Ī", 0},
+ {"J", 1},
+ {"IJ", 0},
+ {"apostrophe", 1},
+ {"Í", 0},
+ {"comma", 1},
+ {"Į", 0},
+ {"asciitilde", 1},
+ {"Ĩ", 0},
+ {"greater", 1},
+ {"Î", 0},
+ {"grave", 1},
+ {"Ì", 0},
+ {"asciicircum", 1},
+ {"Î", 0},
+ {"N", 16},
+ {"less", 1},
+ {"Ň", 0},
+ {"o", 1},
+ {"№", 0},
+ {"equal", 1},
+ {"₦", 0},
+ {"G", 1},
+ {"Ŋ", 0},
+ {"apostrophe", 1},
+ {"Ń", 0},
+ {"O", 1},
+ {"№", 0},
+ {"comma", 1},
+ {"Ņ", 0},
+ {"asciitilde", 1},
+ {"Ñ", 0},
+ {"grave", 362},
+ {"W", 1},
+ {"Ẁ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"a", 1},
+ {"à", 0},
+ {"Greek_IOTA", 1},
+ {"Ὶ", 0},
+ {"Greek_iota", 1},
+ {"ὶ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ờ", 0},
+ {"u", 1},
+ {"ừ", 0},
+ {"O", 1},
+ {"Ờ", 0},
+ {"U", 1},
+ {"Ừ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ầ", 0},
+ {"e", 1},
+ {"ề", 0},
+ {"o", 1},
+ {"ồ", 0},
+ {"E", 1},
+ {"Ề", 0},
+ {"O", 1},
+ {"Ồ", 0},
+ {"A", 1},
+ {"Ầ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὸ", 0},
+ {"Acircumflex", 1},
+ {"Ầ", 0},
+ {"Cyrillic_er", 1},
+ {"р̀", 0},
+ {"e", 1},
+ {"è", 0},
+ {"o", 1},
+ {"ò", 0},
+ {"Udiaeresis", 1},
+ {"Ǜ", 0},
+ {"Greek_upsilon", 1},
+ {"ὺ", 0},
+ {"uhorn", 1},
+ {"ừ", 0},
+ {"space", 1},
+ {"`", 0},
+ {"dead_macron", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"acircumflex", 1},
+ {"ầ", 0},
+ {"Ecircumflex", 1},
+ {"Ề", 0},
+ {"Cyrillic_I", 1},
+ {"Ѝ", 0},
+ {"y", 1},
+ {"ỳ", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ằ", 0},
+ {"A", 1},
+ {"Ằ", 0},
+ {"Cyrillic_O", 1},
+ {"О̀", 0},
+ {"i", 1},
+ {"ì", 0},
+ {"n", 1},
+ {"ǹ", 0},
+ {"Cyrillic_a", 1},
+ {"а̀", 0},
+ {"parenright", 26},
+ {"Greek_IOTA", 1},
+ {"Ἲ", 0},
+ {"Greek_iota", 1},
+ {"ἲ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὂ", 0},
+ {"Greek_upsilon", 1},
+ {"ὒ", 0},
+ {"Greek_epsilon", 1},
+ {"ἒ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἂ", 0},
+ {"Greek_omicron", 1},
+ {"ὂ", 0},
+ {"Greek_eta", 1},
+ {"ἢ", 0},
+ {"Greek_alpha", 1},
+ {"ἂ", 0},
+ {"Greek_ETA", 1},
+ {"Ἢ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἒ", 0},
+ {"Greek_omega", 1},
+ {"ὢ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὢ", 0},
+ {"Ohorn", 1},
+ {"Ờ", 0},
+ {"ohorn", 1},
+ {"ờ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̀", 0},
+ {"Greek_epsilon", 1},
+ {"ὲ", 0},
+ {"Cyrillic_U", 1},
+ {"У̀", 0},
+ {"Ocircumflex", 1},
+ {"Ồ", 0},
+ {"omacron", 1},
+ {"ṑ", 0},
+ {"ocircumflex", 1},
+ {"ồ", 0},
+ {"u", 1},
+ {"ù", 0},
+ {"Greek_ALPHA", 1},
+ {"Ὰ", 0},
+ {"Cyrillic_ie", 1},
+ {"ѐ", 0},
+ {"emacron", 1},
+ {"ḕ", 0},
+ {"E", 1},
+ {"È", 0},
+ {"Greek_iotadieresis", 1},
+ {"ῒ", 0},
+ {"Y", 1},
+ {"Ỳ", 0},
+ {"Cyrillic_i", 1},
+ {"ѝ", 0},
+ {"dead_dasia", 28},
+ {"Greek_IOTA", 1},
+ {"Ἳ", 0},
+ {"Greek_iota", 1},
+ {"ἳ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὃ", 0},
+ {"Greek_upsilon", 1},
+ {"ὓ", 0},
+ {"Greek_epsilon", 1},
+ {"ἓ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἃ", 0},
+ {"Greek_omicron", 1},
+ {"ὃ", 0},
+ {"Greek_eta", 1},
+ {"ἣ", 0},
+ {"Greek_alpha", 1},
+ {"ἃ", 0},
+ {"Greek_ETA", 1},
+ {"Ἣ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἓ", 0},
+ {"Greek_omega", 1},
+ {"ὣ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὓ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ῢ", 0},
+ {"Greek_omicron", 1},
+ {"ὸ", 0},
+ {"Greek_eta", 1},
+ {"ὴ", 0},
+ {"Abreve", 1},
+ {"Ằ", 0},
+ {"dead_psili", 26},
+ {"Greek_IOTA", 1},
+ {"Ἲ", 0},
+ {"Greek_iota", 1},
+ {"ἲ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὂ", 0},
+ {"Greek_upsilon", 1},
+ {"ὒ", 0},
+ {"Greek_epsilon", 1},
+ {"ἒ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἂ", 0},
+ {"Greek_omicron", 1},
+ {"ὂ", 0},
+ {"Greek_eta", 1},
+ {"ἢ", 0},
+ {"Greek_alpha", 1},
+ {"ἂ", 0},
+ {"Greek_ETA", 1},
+ {"Ἢ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἒ", 0},
+ {"Greek_omega", 1},
+ {"ὢ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὢ", 0},
+ {"quotedbl", 8},
+ {"Greek_iota", 1},
+ {"ῒ", 0},
+ {"Greek_upsilon", 1},
+ {"ῢ", 0},
+ {"u", 1},
+ {"ǜ", 0},
+ {"U", 1},
+ {"Ǜ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ờ", 0},
+ {"u", 1},
+ {"ừ", 0},
+ {"O", 1},
+ {"Ờ", 0},
+ {"U", 1},
+ {"Ừ", 0},
+ {"Greek_alpha", 1},
+ {"ὰ", 0},
+ {"ecircumflex", 1},
+ {"ề", 0},
+ {"w", 1},
+ {"ẁ", 0},
+ {"Greek_ETA", 1},
+ {"Ὴ", 0},
+ {"Cyrillic_o", 1},
+ {"о̀", 0},
+ {"Emacron", 1},
+ {"Ḕ", 0},
+ {"underscore", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"O", 1},
+ {"Ò", 0},
+ {"abreve", 1},
+ {"ằ", 0},
+ {"macron", 8},
+ {"e", 1},
+ {"ḕ", 0},
+ {"o", 1},
+ {"ṑ", 0},
+ {"E", 1},
+ {"Ḕ", 0},
+ {"O", 1},
+ {"Ṑ", 0},
+ {"A", 1},
+ {"À", 0},
+ {"Greek_EPSILON", 1},
+ {"Ὲ", 0},
+ {"Cyrillic_A", 1},
+ {"А̀", 0},
+ {"Omacron", 1},
+ {"Ṑ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ѐ", 0},
+ {"Greek_omega", 1},
+ {"ὼ", 0},
+ {"dead_diaeresis", 8},
+ {"Greek_iota", 1},
+ {"ῒ", 0},
+ {"Greek_upsilon", 1},
+ {"ῢ", 0},
+ {"u", 1},
+ {"ǜ", 0},
+ {"U", 1},
+ {"Ǜ", 0},
+ {"Uhorn", 1},
+ {"Ừ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὼ", 0},
+ {"parenleft", 28},
+ {"Greek_IOTA", 1},
+ {"Ἳ", 0},
+ {"Greek_iota", 1},
+ {"ἳ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὃ", 0},
+ {"Greek_upsilon", 1},
+ {"ὓ", 0},
+ {"Greek_epsilon", 1},
+ {"ἓ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἃ", 0},
+ {"Greek_omicron", 1},
+ {"ὃ", 0},
+ {"Greek_eta", 1},
+ {"ἣ", 0},
+ {"Greek_alpha", 1},
+ {"ἃ", 0},
+ {"Greek_ETA", 1},
+ {"Ἣ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἓ", 0},
+ {"Greek_omega", 1},
+ {"ὣ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὣ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὓ", 0},
+ {"udiaeresis", 1},
+ {"ǜ", 0},
+ {"I", 1},
+ {"Ì", 0},
+ {"N", 1},
+ {"Ǹ", 0},
+ {"grave", 24},
+ {"Cyrillic_er", 1},
+ {"р̏", 0},
+ {"Cyrillic_I", 1},
+ {"И̏", 0},
+ {"Cyrillic_O", 1},
+ {"О̏", 0},
+ {"Cyrillic_a", 1},
+ {"а̏", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̏", 0},
+ {"Cyrillic_U", 1},
+ {"У̏", 0},
+ {"Cyrillic_ie", 1},
+ {"е̏", 0},
+ {"Cyrillic_i", 1},
+ {"и̏", 0},
+ {"Cyrillic_o", 1},
+ {"о̏", 0},
+ {"Cyrillic_A", 1},
+ {"А̏", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̏", 0},
+ {"Cyrillic_u", 1},
+ {"у̏", 0},
+ {"U", 1},
+ {"Ù", 0},
+ {"Cyrillic_u", 1},
+ {"у̀", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ầ", 0},
+ {"e", 1},
+ {"ề", 0},
+ {"o", 1},
+ {"ồ", 0},
+ {"E", 1},
+ {"Ề", 0},
+ {"O", 1},
+ {"Ồ", 0},
+ {"A", 1},
+ {"Ầ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὺ", 0},
+ {"U", 106},
+ {"minus", 1},
+ {"Ū", 0},
+ {"g", 1},
+ {"ğ", 0},
+ {"a", 1},
+ {"ă", 0},
+ {"Greek_IOTA", 1},
+ {"Ῐ", 0},
+ {"Greek_iota", 1},
+ {"ῐ", 0},
+ {"exclam", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"e", 1},
+ {"ĕ", 0},
+ {"o", 1},
+ {"ŏ", 0},
+ {"Greek_upsilon", 1},
+ {"ῠ", 0},
+ {"diaeresis", 1},
+ {"Ü", 0},
+ {"dead_belowdot", 4},
+ {"a", 1},
+ {"ặ", 0},
+ {"A", 1},
+ {"Ặ", 0},
+ {"space", 5},
+ {"comma", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"Cyrillic_I", 1},
+ {"Й", 0},
+ {"i", 1},
+ {"ĭ", 0},
+ {"Cyrillic_a", 1},
+ {"ӑ", 0},
+ {"Cyrillic_U", 1},
+ {"Ў", 0},
+ {"u", 1},
+ {"ŭ", 0},
+ {"G", 1},
+ {"Ğ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ᾰ", 0},
+ {"Cyrillic_ie", 1},
+ {"ӗ", 0},
+ {"E", 1},
+ {"Ĕ", 0},
+ {"Cyrillic_i", 1},
+ {"й", 0},
+ {"Cyrillic_zhe", 1},
+ {"ӂ", 0},
+ {"quotedbl", 1},
+ {"Ü", 0},
+ {"cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"Greek_alpha", 1},
+ {"ᾰ", 0},
+ {"acute", 1},
+ {"Ú", 0},
+ {"underscore", 1},
+ {"Ū", 0},
+ {"apostrophe", 1},
+ {"Ú", 0},
+ {"O", 1},
+ {"Ŏ", 0},
+ {"asterisk", 1},
+ {"Ů", 0},
+ {"A", 1},
+ {"Ă", 0},
+ {"Cyrillic_A", 1},
+ {"Ӑ", 0},
+ {"comma", 1},
+ {"Ų", 0},
+ {"asciitilde", 1},
+ {"Ũ", 0},
+ {"greater", 1},
+ {"Û", 0},
+ {"Cyrillic_ZHE", 1},
+ {"Ӂ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ӗ", 0},
+ {"dead_cedilla", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"I", 1},
+ {"Ĭ", 0},
+ {"grave", 1},
+ {"Ù", 0},
+ {"U", 1},
+ {"Ŭ", 0},
+ {"Cyrillic_u", 1},
+ {"ў", 0},
+ {"asciicircum", 1},
+ {"Û", 0},
+ {"Greek_UPSILON", 1},
+ {"Ῠ", 0},
+ {"asciicircum", 214},
+ {"minus", 1},
+ {"¯", 0},
+ {"period", 1},
+ {"·", 0},
+ {"W", 1},
+ {"Ŵ", 0},
+ {"g", 1},
+ {"ĝ", 0},
+ {"a", 1},
+ {"â", 0},
+ {"1", 1},
+ {"¹", 0},
+ {"C", 1},
+ {"Ĉ", 0},
+ {"KP_4", 1},
+ {"⁴", 0},
+ {"exclam", 12},
+ {"a", 1},
+ {"ậ", 0},
+ {"e", 1},
+ {"ệ", 0},
+ {"o", 1},
+ {"ộ", 0},
+ {"E", 1},
+ {"Ệ", 0},
+ {"O", 1},
+ {"Ộ", 0},
+ {"A", 1},
+ {"Ậ", 0},
+ {"Cyrillic_er", 1},
+ {"р̂", 0},
+ {"o", 1},
+ {"ô", 0},
+ {"e", 1},
+ {"ê", 0},
+ {"KP_6", 1},
+ {"⁶", 0},
+ {"dead_belowdot", 12},
+ {"a", 1},
+ {"ậ", 0},
+ {"e", 1},
+ {"ệ", 0},
+ {"o", 1},
+ {"ộ", 0},
+ {"E", 1},
+ {"Ệ", 0},
+ {"O", 1},
+ {"Ộ", 0},
+ {"A", 1},
+ {"Ậ", 0},
+ {"space", 1},
+ {"^", 0},
+ {"KP_8", 1},
+ {"⁸", 0},
+ {"Cyrillic_I", 1},
+ {"И̂", 0},
+ {"y", 1},
+ {"ŷ", 0},
+ {"Cyrillic_O", 1},
+ {"О̂", 0},
+ {"i", 1},
+ {"î", 0},
+ {"KP_9", 1},
+ {"⁹", 0},
+ {"equal", 1},
+ {"⁼", 0},
+ {"KP_Space", 1},
+ {"²", 0},
+ {"7", 1},
+ {"⁷", 0},
+ {"Cyrillic_a", 1},
+ {"а̂", 0},
+ {"j", 1},
+ {"ĵ", 0},
+ {"parenright", 1},
+ {"⁾", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̂", 0},
+ {"KP_7", 1},
+ {"⁷", 0},
+ {"underbar", 24},
+ {"a", 1},
+ {"ª", 0},
+ {"o", 1},
+ {"º", 0},
+ {"l", 1},
+ {"ˡ", 0},
+ {"y", 1},
+ {"ʸ", 0},
+ {"i", 1},
+ {"ⁱ", 0},
+ {"n", 1},
+ {"ⁿ", 0},
+ {"j", 1},
+ {"ʲ", 0},
+ {"x", 1},
+ {"ˣ", 0},
+ {"w", 1},
+ {"ʷ", 0},
+ {"r", 1},
+ {"ʳ", 0},
+ {"s", 1},
+ {"ˢ", 0},
+ {"h", 1},
+ {"ʰ", 0},
+ {"Cyrillic_U", 1},
+ {"У̂", 0},
+ {"u", 1},
+ {"û", 0},
+ {"z", 1},
+ {"ẑ", 0},
+ {"G", 1},
+ {"Ĝ", 0},
+ {"H", 1},
+ {"Ĥ", 0},
+ {"8", 1},
+ {"⁸", 0},
+ {"KP_1", 1},
+ {"¹", 0},
+ {"3", 1},
+ {"³", 0},
+ {"Cyrillic_ie", 1},
+ {"е̂", 0},
+ {"E", 1},
+ {"Ê", 0},
+ {"S", 1},
+ {"Ŝ", 0},
+ {"2", 1},
+ {"²", 0},
+ {"Y", 1},
+ {"Ŷ", 0},
+ {"Cyrillic_i", 1},
+ {"и̂", 0},
+ {"plus", 1},
+ {"⁺", 0},
+ {"6", 1},
+ {"⁶", 0},
+ {"w", 1},
+ {"ŵ", 0},
+ {"Cyrillic_o", 1},
+ {"о̂", 0},
+ {"4", 1},
+ {"⁴", 0},
+ {"KP_3", 1},
+ {"³", 0},
+ {"underscore", 24},
+ {"a", 1},
+ {"ª", 0},
+ {"o", 1},
+ {"º", 0},
+ {"l", 1},
+ {"ˡ", 0},
+ {"y", 1},
+ {"ʸ", 0},
+ {"i", 1},
+ {"ⁱ", 0},
+ {"n", 1},
+ {"ⁿ", 0},
+ {"j", 1},
+ {"ʲ", 0},
+ {"x", 1},
+ {"ˣ", 0},
+ {"w", 1},
+ {"ʷ", 0},
+ {"r", 1},
+ {"ʳ", 0},
+ {"s", 1},
+ {"ˢ", 0},
+ {"h", 1},
+ {"ʰ", 0},
+ {"J", 1},
+ {"Ĵ", 0},
+ {"O", 1},
+ {"Ô", 0},
+ {"s", 1},
+ {"ŝ", 0},
+ {"Z", 1},
+ {"Ẑ", 0},
+ {"KP_0", 1},
+ {"⁰", 0},
+ {"A", 1},
+ {"Â", 0},
+ {"c", 1},
+ {"ĉ", 0},
+ {"KP_Add", 1},
+ {"⁺", 0},
+ {"KP_2", 1},
+ {"²", 0},
+ {"Cyrillic_A", 1},
+ {"А̂", 0},
+ {"slash", 1},
+ {"|", 0},
+ {"5", 1},
+ {"⁵", 0},
+ {"KP_5", 1},
+ {"⁵", 0},
+ {"9", 1},
+ {"⁹", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̂", 0},
+ {"0", 1},
+ {"⁰", 0},
+ {"parenleft", 1},
+ {"⁽", 0},
+ {"h", 1},
+ {"ĥ", 0},
+ {"I", 1},
+ {"Î", 0},
+ {"U", 1},
+ {"Û", 0},
+ {"Cyrillic_u", 1},
+ {"у̂", 0},
+ {"KP_Equal", 1},
+ {"⁼", 0},
+ {"Greek_UPSILON", 4},
+ {"quotedbl", 1},
+ {"Ϋ", 0},
+ {"apostrophe", 1},
+ {"Ύ", 0},
+ {"dead_belowcircumflex", 24},
+ {"e", 1},
+ {"ḙ", 0},
+ {"l", 1},
+ {"ḽ", 0},
+ {"t", 1},
+ {"ṱ", 0},
+ {"n", 1},
+ {"ṋ", 0},
+ {"u", 1},
+ {"ṷ", 0},
+ {"E", 1},
+ {"Ḙ", 0},
+ {"d", 1},
+ {"ḓ", 0},
+ {"D", 1},
+ {"Ḓ", 0},
+ {"L", 1},
+ {"Ḽ", 0},
+ {"T", 1},
+ {"Ṱ", 0},
+ {"N", 1},
+ {"Ṋ", 0},
+ {"U", 1},
+ {"Ṷ", 0},
+ {"dead_caron", 134},
+ {"minus", 1},
+ {"₋", 0},
+ {"g", 1},
+ {"ǧ", 0},
+ {"a", 1},
+ {"ǎ", 0},
+ {"1", 1},
+ {"₁", 0},
+ {"ezh", 1},
+ {"ǯ", 0},
+ {"C", 1},
+ {"Č", 0},
+ {"e", 1},
+ {"ě", 0},
+ {"o", 1},
+ {"ǒ", 0},
+ {"l", 1},
+ {"ľ", 0},
+ {"Udiaeresis", 1},
+ {"Ǚ", 0},
+ {"t", 1},
+ {"ť", 0},
+ {"space", 1},
+ {"ˇ", 0},
+ {"Multi_key", 5},
+ {"quotedbl", 4},
+ {"u", 1},
+ {"ǚ", 0},
+ {"U", 1},
+ {"Ǚ", 0},
+ {"i", 1},
+ {"ǐ", 0},
+ {"k", 1},
+ {"ǩ", 0},
+ {"n", 1},
+ {"ň", 0},
+ {"equal", 1},
+ {"₌", 0},
+ {"dead_caron", 1},
+ {"ˇ", 0},
+ {"7", 1},
+ {"₇", 0},
+ {"j", 1},
+ {"ǰ", 0},
+ {"parenright", 1},
+ {"₎", 0},
+ {"sabovedot", 1},
+ {"ṧ", 0},
+ {"nobreakspace", 1},
+ {"̌", 0},
+ {"V", 1},
+ {"Ǚ", 0},
+ {"u", 1},
+ {"ǔ", 0},
+ {"z", 1},
+ {"ž", 0},
+ {"G", 1},
+ {"Ǧ", 0},
+ {"H", 1},
+ {"Ȟ", 0},
+ {"8", 1},
+ {"₈", 0},
+ {"3", 1},
+ {"₃", 0},
+ {"E", 1},
+ {"Ě", 0},
+ {"S", 1},
+ {"Š", 0},
+ {"2", 1},
+ {"₂", 0},
+ {"d", 1},
+ {"ď", 0},
+ {"D", 1},
+ {"Ď", 0},
+ {"plus", 1},
+ {"₊", 0},
+ {"6", 1},
+ {"₆", 0},
+ {"dead_abovedot", 4},
+ {"S", 1},
+ {"Ṧ", 0},
+ {"s", 1},
+ {"ṧ", 0},
+ {"4", 1},
+ {"₄", 0},
+ {"v", 1},
+ {"ǚ", 0},
+ {"O", 1},
+ {"Ǒ", 0},
+ {"r", 1},
+ {"ř", 0},
+ {"s", 1},
+ {"š", 0},
+ {"Z", 1},
+ {"Ž", 0},
+ {"EZH", 1},
+ {"Ǯ", 0},
+ {"A", 1},
+ {"Ǎ", 0},
+ {"R", 1},
+ {"Ř", 0},
+ {"c", 1},
+ {"č", 0},
+ {"L", 1},
+ {"Ľ", 0},
+ {"T", 1},
+ {"Ť", 0},
+ {"5", 1},
+ {"₅", 0},
+ {"K", 1},
+ {"Ǩ", 0},
+ {"9", 1},
+ {"₉", 0},
+ {"0", 1},
+ {"₀", 0},
+ {"Sabovedot", 1},
+ {"Ṧ", 0},
+ {"dead_diaeresis", 4},
+ {"u", 1},
+ {"ǚ", 0},
+ {"U", 1},
+ {"Ǚ", 0},
+ {"parenleft", 1},
+ {"₍", 0},
+ {"h", 1},
+ {"ȟ", 0},
+ {"udiaeresis", 1},
+ {"ǚ", 0},
+ {"I", 1},
+ {"Ǐ", 0},
+ {"N", 1},
+ {"Ň", 0},
+ {"U", 1},
+ {"Ǔ", 0},
+ {"dead_tilde", 266},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"a", 1},
+ {"ã", 0},
+ {"Greek_iota", 1},
+ {"ῖ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ỡ", 0},
+ {"u", 1},
+ {"ữ", 0},
+ {"O", 1},
+ {"Ỡ", 0},
+ {"U", 1},
+ {"Ữ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ẫ", 0},
+ {"e", 1},
+ {"ễ", 0},
+ {"o", 1},
+ {"ỗ", 0},
+ {"E", 1},
+ {"Ễ", 0},
+ {"O", 1},
+ {"Ỗ", 0},
+ {"A", 1},
+ {"Ẫ", 0},
+ {"Acircumflex", 1},
+ {"Ẫ", 0},
+ {"less", 1},
+ {"≲", 0},
+ {"Oacute", 1},
+ {"Ṍ", 0},
+ {"e", 1},
+ {"ẽ", 0},
+ {"o", 1},
+ {"õ", 0},
+ {"Greek_upsilon", 1},
+ {"ῦ", 0},
+ {"uhorn", 1},
+ {"ữ", 0},
+ {"space", 1},
+ {"~", 0},
+ {"dead_macron", 4},
+ {"o", 1},
+ {"ȭ", 0},
+ {"O", 1},
+ {"Ȭ", 0},
+ {"acircumflex", 1},
+ {"ẫ", 0},
+ {"Ecircumflex", 1},
+ {"Ễ", 0},
+ {"y", 1},
+ {"ỹ", 0},
+ {"Multi_key", 77},
+ {"b", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"parenright", 18},
+ {"Greek_IOTA", 1},
+ {"Ἶ", 0},
+ {"Greek_iota", 1},
+ {"ἶ", 0},
+ {"Greek_upsilon", 1},
+ {"ὖ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἆ", 0},
+ {"Greek_eta", 1},
+ {"ἦ", 0},
+ {"Greek_alpha", 1},
+ {"ἆ", 0},
+ {"Greek_ETA", 1},
+ {"Ἦ", 0},
+ {"Greek_omega", 1},
+ {"ὦ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὦ", 0},
+ {"quotedbl", 4},
+ {"Greek_iota", 1},
+ {"ῗ", 0},
+ {"Greek_upsilon", 1},
+ {"ῧ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ỡ", 0},
+ {"u", 1},
+ {"ữ", 0},
+ {"O", 1},
+ {"Ỡ", 0},
+ {"U", 1},
+ {"Ữ", 0},
+ {"parenleft", 20},
+ {"Greek_IOTA", 1},
+ {"Ἷ", 0},
+ {"Greek_iota", 1},
+ {"ἷ", 0},
+ {"Greek_upsilon", 1},
+ {"ὗ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἇ", 0},
+ {"Greek_eta", 1},
+ {"ἧ", 0},
+ {"Greek_alpha", 1},
+ {"ἇ", 0},
+ {"Greek_ETA", 1},
+ {"Ἧ", 0},
+ {"Greek_omega", 1},
+ {"ὧ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὧ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὗ", 0},
+ {"U", 4},
+ {"a", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ẵ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ẫ", 0},
+ {"e", 1},
+ {"ễ", 0},
+ {"o", 1},
+ {"ỗ", 0},
+ {"E", 1},
+ {"Ễ", 0},
+ {"O", 1},
+ {"Ỗ", 0},
+ {"A", 1},
+ {"Ẫ", 0},
+ {"oacute", 1},
+ {"ṍ", 0},
+ {"i", 1},
+ {"ĩ", 0},
+ {"n", 1},
+ {"ñ", 0},
+ {"equal", 1},
+ {"≃", 0},
+ {"dead_tilde", 1},
+ {"~", 0},
+ {"Uacute", 1},
+ {"Ṹ", 0},
+ {"Ohorn", 1},
+ {"Ỡ", 0},
+ {"ohorn", 1},
+ {"ỡ", 0},
+ {"nobreakspace", 1},
+ {"̃", 0},
+ {"V", 1},
+ {"Ṽ", 0},
+ {"Ocircumflex", 1},
+ {"Ỗ", 0},
+ {"omacron", 1},
+ {"ȭ", 0},
+ {"uacute", 1},
+ {"ṹ", 0},
+ {"ocircumflex", 1},
+ {"ỗ", 0},
+ {"u", 1},
+ {"ũ", 0},
+ {"E", 1},
+ {"Ẽ", 0},
+ {"Greek_iotadieresis", 1},
+ {"ῗ", 0},
+ {"Y", 1},
+ {"Ỹ", 0},
+ {"dead_dasia", 20},
+ {"Greek_IOTA", 1},
+ {"Ἷ", 0},
+ {"Greek_iota", 1},
+ {"ἷ", 0},
+ {"Greek_upsilon", 1},
+ {"ὗ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἇ", 0},
+ {"Greek_eta", 1},
+ {"ἧ", 0},
+ {"Greek_alpha", 1},
+ {"ἇ", 0},
+ {"Greek_ETA", 1},
+ {"Ἧ", 0},
+ {"Greek_omega", 1},
+ {"ὧ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὧ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὗ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ῧ", 0},
+ {"odiaeresis", 1},
+ {"ṏ", 0},
+ {"Greek_eta", 1},
+ {"ῆ", 0},
+ {"Abreve", 1},
+ {"Ẵ", 0},
+ {"dead_psili", 18},
+ {"Greek_IOTA", 1},
+ {"Ἶ", 0},
+ {"Greek_iota", 1},
+ {"ἶ", 0},
+ {"Greek_upsilon", 1},
+ {"ὖ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἆ", 0},
+ {"Greek_eta", 1},
+ {"ἦ", 0},
+ {"Greek_alpha", 1},
+ {"ἆ", 0},
+ {"Greek_ETA", 1},
+ {"Ἦ", 0},
+ {"Greek_omega", 1},
+ {"ὦ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὦ", 0},
+ {"Greek_alpha", 1},
+ {"ᾶ", 0},
+ {"ecircumflex", 1},
+ {"ễ", 0},
+ {"v", 1},
+ {"ṽ", 0},
+ {"O", 1},
+ {"Õ", 0},
+ {"abreve", 1},
+ {"ẵ", 0},
+ {"A", 1},
+ {"Ã", 0},
+ {"Odiaeresis", 1},
+ {"Ṏ", 0},
+ {"greater", 1},
+ {"≳", 0},
+ {"Omacron", 1},
+ {"Ȭ", 0},
+ {"Greek_omega", 1},
+ {"ῶ", 0},
+ {"dead_diaeresis", 8},
+ {"Greek_iota", 1},
+ {"ῗ", 0},
+ {"o", 1},
+ {"ṏ", 0},
+ {"Greek_upsilon", 1},
+ {"ῧ", 0},
+ {"O", 1},
+ {"Ṏ", 0},
+ {"Uhorn", 1},
+ {"Ữ", 0},
+ {"dead_acute", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"I", 1},
+ {"Ĩ", 0},
+ {"N", 1},
+ {"Ñ", 0},
+ {"U", 1},
+ {"Ũ", 0},
+ {"dead_belowcomma", 14},
+ {"t", 1},
+ {"ț", 0},
+ {"space", 1},
+ {",", 0},
+ {"dead_belowcomma", 1},
+ {",", 0},
+ {"nobreakspace", 1},
+ {"̦", 0},
+ {"S", 1},
+ {"Ș", 0},
+ {"s", 1},
+ {"ș", 0},
+ {"T", 1},
+ {"Ț", 0},
+ {"dead_doubleacute", 18},
+ {"o", 1},
+ {"ő", 0},
+ {"space", 1},
+ {"˝", 0},
+ {"Cyrillic_U", 1},
+ {"Ӳ", 0},
+ {"dead_doubleacute", 1},
+ {"˝", 0},
+ {"nobreakspace", 1},
+ {"̋", 0},
+ {"u", 1},
+ {"ű", 0},
+ {"O", 1},
+ {"Ő", 0},
+ {"U", 1},
+ {"Ű", 0},
+ {"Cyrillic_u", 1},
+ {"ӳ", 0},
+ {"dead_abovering", 27},
+ {"a", 1},
+ {"å", 0},
+ {"space", 1},
+ {"°", 0},
+ {"y", 1},
+ {"ẙ", 0},
+ {"dead_abovering", 1},
+ {"°", 0},
+ {"nobreakspace", 1},
+ {"̊", 0},
+ {"u", 1},
+ {"ů", 0},
+ {"w", 1},
+ {"ẘ", 0},
+ {"A", 1},
+ {"Å", 0},
+ {"Aacute", 1},
+ {"Ǻ", 0},
+ {"aacute", 1},
+ {"ǻ", 0},
+ {"dead_acute", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"U", 1},
+ {"Ů", 0},
+ {"Greek_accentdieresis", 4},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"dead_voiced_sound", 46},
+ {"kana_KE", 1},
+ {"ゲ", 0},
+ {"kana_SA", 1},
+ {"ザ", 0},
+ {"kana_SE", 1},
+ {"ゼ", 0},
+ {"kana_SU", 1},
+ {"ズ", 0},
+ {"kana_WO", 1},
+ {"ヺ", 0},
+ {"kana_TE", 1},
+ {"デ", 0},
+ {"kana_HO", 1},
+ {"ボ", 0},
+ {"kana_HI", 1},
+ {"ビ", 0},
+ {"kana_WA", 1},
+ {"ヷ", 0},
+ {"kana_CHI", 1},
+ {"ヂ", 0},
+ {"kana_HA", 1},
+ {"バ", 0},
+ {"kana_HE", 1},
+ {"ベ", 0},
+ {"kana_KO", 1},
+ {"ゴ", 0},
+ {"kana_FU", 1},
+ {"ブ", 0},
+ {"kana_KU", 1},
+ {"グ", 0},
+ {"kana_U", 1},
+ {"ヴ", 0},
+ {"kana_TO", 1},
+ {"ド", 0},
+ {"kana_TA", 1},
+ {"ダ", 0},
+ {"kana_KA", 1},
+ {"ガ", 0},
+ {"kana_KI", 1},
+ {"ギ", 0},
+ {"kana_SO", 1},
+ {"ゾ", 0},
+ {"kana_TSU", 1},
+ {"ヅ", 0},
+ {"kana_SHI", 1},
+ {"ジ", 0},
+ {"dead_belowtilde", 14},
+ {"e", 1},
+ {"ḛ", 0},
+ {"i", 1},
+ {"ḭ", 0},
+ {"u", 1},
+ {"ṵ", 0},
+ {"E", 1},
+ {"Ḛ", 0},
+ {"plus", 1},
+ {"⨦", 0},
+ {"I", 1},
+ {"Ḭ", 0},
+ {"U", 1},
+ {"Ṵ", 0},
+ {"dead_ogonek", 35},
+ {"a", 1},
+ {"ą", 0},
+ {"e", 1},
+ {"ę", 0},
+ {"o", 1},
+ {"ǫ", 0},
+ {"space", 1},
+ {"˛", 0},
+ {"dead_macron", 4},
+ {"o", 1},
+ {"ǭ", 0},
+ {"O", 1},
+ {"Ǭ", 0},
+ {"i", 1},
+ {"į", 0},
+ {"nobreakspace", 1},
+ {"̨", 0},
+ {"omacron", 1},
+ {"ǭ", 0},
+ {"u", 1},
+ {"ų", 0},
+ {"E", 1},
+ {"Ę", 0},
+ {"dead_ogonek", 1},
+ {"˛", 0},
+ {"O", 1},
+ {"Ǫ", 0},
+ {"A", 1},
+ {"Ą", 0},
+ {"Omacron", 1},
+ {"Ǭ", 0},
+ {"I", 1},
+ {"Į", 0},
+ {"U", 1},
+ {"Ų", 0},
+ {"dead_dasia", 32},
+ {"Greek_IOTA", 1},
+ {"Ἱ", 0},
+ {"Greek_iota", 1},
+ {"ἱ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὁ", 0},
+ {"Greek_upsilon", 1},
+ {"ὑ", 0},
+ {"Greek_RHO", 1},
+ {"Ῥ", 0},
+ {"Greek_epsilon", 1},
+ {"ἑ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἁ", 0},
+ {"Greek_omicron", 1},
+ {"ὁ", 0},
+ {"Greek_eta", 1},
+ {"ἡ", 0},
+ {"Greek_rho", 1},
+ {"ῥ", 0},
+ {"Greek_alpha", 1},
+ {"ἁ", 0},
+ {"Greek_ETA", 1},
+ {"Ἡ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἑ", 0},
+ {"Greek_omega", 1},
+ {"ὡ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὡ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὑ", 0},
+ {"dead_iota", 491},
+ {"dead_grave", 59},
+ {"Multi_key", 26},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"Greek_eta", 1},
+ {"ῂ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"Greek_alpha", 1},
+ {"ᾲ", 0},
+ {"Greek_omega", 1},
+ {"ῲ", 0},
+ {"space", 1},
+ {"ͺ", 0},
+ {"Multi_key", 262},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾈ", 0},
+ {"Greek_eta", 1},
+ {"ᾐ", 0},
+ {"Greek_alpha", 1},
+ {"ᾀ", 0},
+ {"Greek_ETA", 1},
+ {"ᾘ", 0},
+ {"Greek_omega", 1},
+ {"ᾠ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾨ", 0},
+ {"acute", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"apostrophe", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"asciitilde", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"Greek_eta", 1},
+ {"ῇ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"Greek_alpha", 1},
+ {"ᾷ", 0},
+ {"Greek_omega", 1},
+ {"ῷ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾉ", 0},
+ {"Greek_eta", 1},
+ {"ᾑ", 0},
+ {"Greek_alpha", 1},
+ {"ᾁ", 0},
+ {"Greek_ETA", 1},
+ {"ᾙ", 0},
+ {"Greek_omega", 1},
+ {"ᾡ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾩ", 0},
+ {"grave", 58},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"Greek_eta", 1},
+ {"ῂ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾊ", 0},
+ {"Greek_eta", 1},
+ {"ᾒ", 0},
+ {"Greek_alpha", 1},
+ {"ᾂ", 0},
+ {"Greek_ETA", 1},
+ {"ᾚ", 0},
+ {"Greek_omega", 1},
+ {"ᾢ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾪ", 0},
+ {"Greek_alpha", 1},
+ {"ᾲ", 0},
+ {"Greek_omega", 1},
+ {"ῲ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾋ", 0},
+ {"Greek_eta", 1},
+ {"ᾓ", 0},
+ {"Greek_alpha", 1},
+ {"ᾃ", 0},
+ {"Greek_ETA", 1},
+ {"ᾛ", 0},
+ {"Greek_omega", 1},
+ {"ᾣ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾫ", 0},
+ {"dead_tilde", 59},
+ {"Multi_key", 26},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾏ", 0},
+ {"Greek_eta", 1},
+ {"ᾗ", 0},
+ {"Greek_alpha", 1},
+ {"ᾇ", 0},
+ {"Greek_ETA", 1},
+ {"ᾟ", 0},
+ {"Greek_omega", 1},
+ {"ᾧ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾯ", 0},
+ {"Greek_eta", 1},
+ {"ῇ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾎ", 0},
+ {"Greek_eta", 1},
+ {"ᾖ", 0},
+ {"Greek_alpha", 1},
+ {"ᾆ", 0},
+ {"Greek_ETA", 1},
+ {"ᾞ", 0},
+ {"Greek_omega", 1},
+ {"ᾦ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾮ", 0},
+ {"Greek_alpha", 1},
+ {"ᾷ", 0},
+ {"Greek_omega", 1},
+ {"ῷ", 0},
+ {"Greek_ALPHA", 1},
+ {"ᾼ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾉ", 0},
+ {"Greek_eta", 1},
+ {"ᾑ", 0},
+ {"Greek_alpha", 1},
+ {"ᾁ", 0},
+ {"Greek_ETA", 1},
+ {"ᾙ", 0},
+ {"Greek_omega", 1},
+ {"ᾡ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾩ", 0},
+ {"Greek_eta", 1},
+ {"ῃ", 0},
+ {"dead_iota", 1},
+ {"ͺ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾈ", 0},
+ {"Greek_eta", 1},
+ {"ᾐ", 0},
+ {"Greek_alpha", 1},
+ {"ᾀ", 0},
+ {"Greek_ETA", 1},
+ {"ᾘ", 0},
+ {"Greek_omega", 1},
+ {"ᾠ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾨ", 0},
+ {"Greek_alpha", 1},
+ {"ᾳ", 0},
+ {"Greek_ETA", 1},
+ {"ῌ", 0},
+ {"Greek_omegaaccent", 1},
+ {"ῴ", 0},
+ {"Greek_omega", 1},
+ {"ῳ", 0},
+ {"Greek_OMEGA", 1},
+ {"ῼ", 0},
+ {"dead_acute", 59},
+ {"Multi_key", 26},
+ {"parenright", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"parenleft", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"dead_dasia", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾍ", 0},
+ {"Greek_eta", 1},
+ {"ᾕ", 0},
+ {"Greek_alpha", 1},
+ {"ᾅ", 0},
+ {"Greek_ETA", 1},
+ {"ᾝ", 0},
+ {"Greek_omega", 1},
+ {"ᾥ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾭ", 0},
+ {"Greek_eta", 1},
+ {"ῄ", 0},
+ {"dead_psili", 12},
+ {"Greek_ALPHA", 1},
+ {"ᾌ", 0},
+ {"Greek_eta", 1},
+ {"ᾔ", 0},
+ {"Greek_alpha", 1},
+ {"ᾄ", 0},
+ {"Greek_ETA", 1},
+ {"ᾜ", 0},
+ {"Greek_omega", 1},
+ {"ᾤ", 0},
+ {"Greek_OMEGA", 1},
+ {"ᾬ", 0},
+ {"Greek_alpha", 1},
+ {"ᾴ", 0},
+ {"Greek_omega", 1},
+ {"ῴ", 0},
+ {"Greek_alphaaccent", 1},
+ {"ᾴ", 0},
+ {"Greek_etaaccent", 1},
+ {"ῄ", 0},
+ {"dead_greek", 121},
+ {"W", 1},
+ {"Ω", 0},
+ {"g", 1},
+ {"γ", 0},
+ {"a", 1},
+ {"α", 0},
+ {"e", 1},
+ {"ε", 0},
+ {"F", 1},
+ {"Φ", 0},
+ {"o", 1},
+ {"ο", 0},
+ {"l", 1},
+ {"λ", 0},
+ {"t", 1},
+ {"τ", 0},
+ {"space", 1},
+ {"µ", 0},
+ {"dead_macron", 12},
+ {"a", 1},
+ {"ᾱ", 0},
+ {"i", 1},
+ {"ῑ", 0},
+ {"u", 1},
+ {"ῡ", 0},
+ {"A", 1},
+ {"Ᾱ", 0},
+ {"I", 1},
+ {"Ῑ", 0},
+ {"U", 1},
+ {"Ῡ", 0},
+ {"Q", 1},
+ {"Χ", 0},
+ {"y", 1},
+ {"ψ", 0},
+ {"b", 1},
+ {"β", 0},
+ {"i", 1},
+ {"ι", 0},
+ {"k", 1},
+ {"κ", 0},
+ {"n", 1},
+ {"ν", 0},
+ {"j", 1},
+ {"θ", 0},
+ {"x", 1},
+ {"ξ", 0},
+ {"q", 1},
+ {"χ", 0},
+ {"nobreakspace", 1},
+ {"µ", 0},
+ {"u", 1},
+ {"υ", 0},
+ {"z", 1},
+ {"ζ", 0},
+ {"G", 1},
+ {"Γ", 0},
+ {"H", 1},
+ {"Η", 0},
+ {"E", 1},
+ {"Ε", 0},
+ {"S", 1},
+ {"Σ", 0},
+ {"Y", 1},
+ {"Ψ", 0},
+ {"f", 1},
+ {"φ", 0},
+ {"d", 1},
+ {"δ", 0},
+ {"dead_greek", 1},
+ {"µ", 0},
+ {"D", 1},
+ {"Δ", 0},
+ {"w", 1},
+ {"ω", 0},
+ {"p", 1},
+ {"π", 0},
+ {"J", 1},
+ {"Θ", 0},
+ {"P", 1},
+ {"Π", 0},
+ {"M", 1},
+ {"Μ", 0},
+ {"O", 1},
+ {"Ο", 0},
+ {"m", 1},
+ {"μ", 0},
+ {"r", 1},
+ {"ρ", 0},
+ {"s", 1},
+ {"σ", 0},
+ {"Z", 1},
+ {"Ζ", 0},
+ {"dead_stroke", 2},
+ {"r", 1},
+ {"ϼ", 0},
+ {"A", 1},
+ {"Α", 0},
+ {"R", 1},
+ {"Ρ", 0},
+ {"L", 1},
+ {"Λ", 0},
+ {"T", 1},
+ {"Τ", 0},
+ {"dead_hook", 2},
+ {"U", 1},
+ {"ϒ", 0},
+ {"K", 1},
+ {"Κ", 0},
+ {"B", 1},
+ {"Β", 0},
+ {"X", 1},
+ {"Ξ", 0},
+ {"h", 1},
+ {"η", 0},
+ {"I", 1},
+ {"Ι", 0},
+ {"N", 1},
+ {"Ν", 0},
+ {"U", 1},
+ {"Υ", 0},
+ {"dead_invertedbreve", 24},
+ {"Cyrillic_er", 1},
+ {"р̑", 0},
+ {"Cyrillic_I", 1},
+ {"И̑", 0},
+ {"Cyrillic_O", 1},
+ {"О̑", 0},
+ {"Cyrillic_a", 1},
+ {"а̑", 0},
+ {"Cyrillic_ER", 1},
+ {"Р̑", 0},
+ {"Cyrillic_U", 1},
+ {"У̑", 0},
+ {"Cyrillic_ie", 1},
+ {"е̑", 0},
+ {"Cyrillic_i", 1},
+ {"и̑", 0},
+ {"Cyrillic_o", 1},
+ {"о̑", 0},
+ {"Cyrillic_A", 1},
+ {"А̑", 0},
+ {"Cyrillic_IE", 1},
+ {"Е̑", 0},
+ {"Cyrillic_u", 1},
+ {"у̑", 0},
+ {"dead_psili", 28},
+ {"Greek_IOTA", 1},
+ {"Ἰ", 0},
+ {"Greek_iota", 1},
+ {"ἰ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὀ", 0},
+ {"Greek_upsilon", 1},
+ {"ὐ", 0},
+ {"Greek_epsilon", 1},
+ {"ἐ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἀ", 0},
+ {"Greek_omicron", 1},
+ {"ὀ", 0},
+ {"Greek_eta", 1},
+ {"ἠ", 0},
+ {"Greek_rho", 1},
+ {"ῤ", 0},
+ {"Greek_alpha", 1},
+ {"ἀ", 0},
+ {"Greek_ETA", 1},
+ {"Ἠ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἐ", 0},
+ {"Greek_omega", 1},
+ {"ὠ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὠ", 0},
+ {"dead_abovedot", 159},
+ {"W", 1},
+ {"Ẇ", 0},
+ {"g", 1},
+ {"ġ", 0},
+ {"a", 1},
+ {"ȧ", 0},
+ {"C", 1},
+ {"Ċ", 0},
+ {"e", 1},
+ {"ė", 0},
+ {"F", 1},
+ {"Ḟ", 0},
+ {"o", 1},
+ {"ȯ", 0},
+ {"l", 1},
+ {"ŀ", 0},
+ {"t", 1},
+ {"ṫ", 0},
+ {"dead_belowdot", 4},
+ {"S", 1},
+ {"Ṩ", 0},
+ {"s", 1},
+ {"ṩ", 0},
+ {"space", 1},
+ {"˙", 0},
+ {"dead_macron", 8},
+ {"a", 1},
+ {"ǡ", 0},
+ {"o", 1},
+ {"ȱ", 0},
+ {"O", 1},
+ {"Ȱ", 0},
+ {"A", 1},
+ {"Ǡ", 0},
+ {"y", 1},
+ {"ẏ", 0},
+ {"b", 1},
+ {"ḃ", 0},
+ {"Multi_key", 23},
+ {"exclam", 4},
+ {"S", 1},
+ {"Ṩ", 0},
+ {"s", 1},
+ {"ṩ", 0},
+ {"f", 2},
+ {"s", 1},
+ {"ẛ", 0},
+ {"acute", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"apostrophe", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"c", 4},
+ {"S", 1},
+ {"Ṧ", 0},
+ {"s", 1},
+ {"ṧ", 0},
+ {"i", 1},
+ {"ı", 0},
+ {"n", 1},
+ {"ṅ", 0},
+ {"dead_caron", 4},
+ {"S", 1},
+ {"Ṧ", 0},
+ {"s", 1},
+ {"ṧ", 0},
+ {"j", 1},
+ {"ȷ", 0},
+ {"x", 1},
+ {"ẋ", 0},
+ {"amacron", 1},
+ {"ǡ", 0},
+ {"nobreakspace", 1},
+ {"̇", 0},
+ {"omacron", 1},
+ {"ȱ", 0},
+ {"z", 1},
+ {"ż", 0},
+ {"G", 1},
+ {"Ġ", 0},
+ {"Sacute", 1},
+ {"Ṥ", 0},
+ {"H", 1},
+ {"Ḣ", 0},
+ {"E", 1},
+ {"Ė", 0},
+ {"S", 1},
+ {"Ṡ", 0},
+ {"Y", 1},
+ {"Ẏ", 0},
+ {"scaron", 1},
+ {"ṧ", 0},
+ {"f", 1},
+ {"ḟ", 0},
+ {"d", 1},
+ {"ḋ", 0},
+ {"Scaron", 1},
+ {"Ṧ", 0},
+ {"D", 1},
+ {"Ḋ", 0},
+ {"dead_abovedot", 1},
+ {"˙", 0},
+ {"w", 1},
+ {"ẇ", 0},
+ {"p", 1},
+ {"ṗ", 0},
+ {"P", 1},
+ {"Ṗ", 0},
+ {"M", 1},
+ {"Ṁ", 0},
+ {"O", 1},
+ {"Ȯ", 0},
+ {"m", 1},
+ {"ṁ", 0},
+ {"r", 1},
+ {"ṙ", 0},
+ {"s", 1},
+ {"ṡ", 0},
+ {"Z", 1},
+ {"Ż", 0},
+ {"sacute", 1},
+ {"ṥ", 0},
+ {"dead_stroke", 2},
+ {"j", 1},
+ {"ɟ", 0},
+ {"A", 1},
+ {"Ȧ", 0},
+ {"R", 1},
+ {"Ṙ", 0},
+ {"c", 1},
+ {"ċ", 0},
+ {"L", 1},
+ {"Ŀ", 0},
+ {"T", 1},
+ {"Ṫ", 0},
+ {"Omacron", 1},
+ {"Ȱ", 0},
+ {"B", 1},
+ {"Ḃ", 0},
+ {"Amacron", 1},
+ {"Ǡ", 0},
+ {"dead_acute", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"X", 1},
+ {"Ẋ", 0},
+ {"h", 1},
+ {"ḣ", 0},
+ {"I", 1},
+ {"İ", 0},
+ {"N", 1},
+ {"Ṅ", 0},
+ {"dead_double_grave", 24},
+ {"a", 1},
+ {"ȁ", 0},
+ {"e", 1},
+ {"ȅ", 0},
+ {"o", 1},
+ {"ȍ", 0},
+ {"i", 1},
+ {"ȉ", 0},
+ {"u", 1},
+ {"ȕ", 0},
+ {"E", 1},
+ {"Ȅ", 0},
+ {"O", 1},
+ {"Ȍ", 0},
+ {"r", 1},
+ {"ȑ", 0},
+ {"A", 1},
+ {"Ȁ", 0},
+ {"R", 1},
+ {"Ȑ", 0},
+ {"I", 1},
+ {"Ȉ", 0},
+ {"U", 1},
+ {"Ȕ", 0},
+ {"dead_semivoiced_sound", 10},
+ {"kana_HO", 1},
+ {"ポ", 0},
+ {"kana_HI", 1},
+ {"ピ", 0},
+ {"kana_HA", 1},
+ {"パ", 0},
+ {"kana_HE", 1},
+ {"ペ", 0},
+ {"kana_FU", 1},
+ {"プ", 0},
+ {"dead_stroke", 101},
+ {"g", 1},
+ {"ǥ", 0},
+ {"a", 1},
+ {"ⱥ", 0},
+ {"C", 1},
+ {"Ȼ", 0},
+ {"less", 1},
+ {"≮", 0},
+ {"Oacute", 1},
+ {"Ǿ", 0},
+ {"e", 1},
+ {"ɇ", 0},
+ {"o", 1},
+ {"ø", 0},
+ {"l", 1},
+ {"ł", 0},
+ {"t", 1},
+ {"ŧ", 0},
+ {"space", 1},
+ {"/", 0},
+ {"y", 1},
+ {"ɏ", 0},
+ {"b", 1},
+ {"ƀ", 0},
+ {"oacute", 1},
+ {"ǿ", 0},
+ {"i", 1},
+ {"ɨ", 0},
+ {"equal", 1},
+ {"≠", 0},
+ {"j", 1},
+ {"ɉ", 0},
+ {"nobreakspace", 1},
+ {"̸", 0},
+ {"u", 1},
+ {"ʉ", 0},
+ {"greaterthanequal", 1},
+ {"≱", 0},
+ {"z", 1},
+ {"ƶ", 0},
+ {"G", 1},
+ {"Ǥ", 0},
+ {"H", 1},
+ {"Ħ", 0},
+ {"E", 1},
+ {"Ɇ", 0},
+ {"2", 1},
+ {"ƻ", 0},
+ {"Y", 1},
+ {"Ɏ", 0},
+ {"d", 1},
+ {"đ", 0},
+ {"dead_greek", 2},
+ {"r", 1},
+ {"ϼ", 0},
+ {"D", 1},
+ {"Đ", 0},
+ {"dead_abovedot", 2},
+ {"j", 1},
+ {"ɟ", 0},
+ {"lessthanequal", 1},
+ {"≰", 0},
+ {"p", 1},
+ {"ᵽ", 0},
+ {"J", 1},
+ {"Ɉ", 0},
+ {"P", 1},
+ {"Ᵽ", 0},
+ {"O", 1},
+ {"Ø", 0},
+ {"r", 1},
+ {"ɍ", 0},
+ {"Z", 1},
+ {"Ƶ", 0},
+ {"dead_stroke", 1},
+ {"/", 0},
+ {"A", 1},
+ {"Ⱥ", 0},
+ {"R", 1},
+ {"Ɍ", 0},
+ {"c", 1},
+ {"ȼ", 0},
+ {"L", 1},
+ {"Ł", 0},
+ {"T", 1},
+ {"Ŧ", 0},
+ {"greater", 1},
+ {"≯", 0},
+ {"B", 1},
+ {"Ƀ", 0},
+ {"dead_acute", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"h", 1},
+ {"ħ", 0},
+ {"I", 1},
+ {"Ɨ", 0},
+ {"U", 1},
+ {"Ʉ", 0},
+ {"dead_hook", 179},
+ {"W", 1},
+ {"Ⱳ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"g", 1},
+ {"ɠ", 0},
+ {"a", 1},
+ {"ả", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ẩ", 0},
+ {"e", 1},
+ {"ể", 0},
+ {"o", 1},
+ {"ổ", 0},
+ {"E", 1},
+ {"Ể", 0},
+ {"O", 1},
+ {"Ổ", 0},
+ {"A", 1},
+ {"Ẩ", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ở", 0},
+ {"u", 1},
+ {"ử", 0},
+ {"O", 1},
+ {"Ở", 0},
+ {"U", 1},
+ {"Ử", 0},
+ {"Acircumflex", 1},
+ {"Ẩ", 0},
+ {"C", 1},
+ {"Ƈ", 0},
+ {"e", 1},
+ {"ẻ", 0},
+ {"F", 1},
+ {"Ƒ", 0},
+ {"o", 1},
+ {"ỏ", 0},
+ {"t", 1},
+ {"ƭ", 0},
+ {"schwa", 1},
+ {"ɚ", 0},
+ {"uhorn", 1},
+ {"ử", 0},
+ {"space", 1},
+ {"̉", 0},
+ {"acircumflex", 1},
+ {"ẩ", 0},
+ {"Ecircumflex", 1},
+ {"Ể", 0},
+ {"y", 1},
+ {"ỷ", 0},
+ {"b", 1},
+ {"ɓ", 0},
+ {"Multi_key", 32},
+ {"b", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ở", 0},
+ {"u", 1},
+ {"ử", 0},
+ {"O", 1},
+ {"Ở", 0},
+ {"U", 1},
+ {"Ử", 0},
+ {"U", 4},
+ {"a", 1},
+ {"ẳ", 0},
+ {"A", 1},
+ {"Ẳ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ẩ", 0},
+ {"e", 1},
+ {"ể", 0},
+ {"o", 1},
+ {"ổ", 0},
+ {"E", 1},
+ {"Ể", 0},
+ {"O", 1},
+ {"Ổ", 0},
+ {"A", 1},
+ {"Ẩ", 0},
+ {"i", 1},
+ {"ỉ", 0},
+ {"k", 1},
+ {"ƙ", 0},
+ {"n", 1},
+ {"ɲ", 0},
+ {"Ohorn", 1},
+ {"Ở", 0},
+ {"ohorn", 1},
+ {"ở", 0},
+ {"q", 1},
+ {"ʠ", 0},
+ {"nobreakspace", 1},
+ {"̉", 0},
+ {"V", 1},
+ {"Ʋ", 0},
+ {"Ocircumflex", 1},
+ {"Ổ", 0},
+ {"ocircumflex", 1},
+ {"ổ", 0},
+ {"u", 1},
+ {"ủ", 0},
+ {"z", 1},
+ {"ȥ", 0},
+ {"G", 1},
+ {"Ɠ", 0},
+ {"E", 1},
+ {"Ẻ", 0},
+ {"Y", 1},
+ {"Ỷ", 0},
+ {"f", 1},
+ {"ƒ", 0},
+ {"d", 1},
+ {"ɗ", 0},
+ {"dead_greek", 2},
+ {"U", 1},
+ {"ϒ", 0},
+ {"D", 1},
+ {"Ɗ", 0},
+ {"Abreve", 1},
+ {"Ẳ", 0},
+ {"ecircumflex", 1},
+ {"ể", 0},
+ {"w", 1},
+ {"ⱳ", 0},
+ {"p", 1},
+ {"ƥ", 0},
+ {"v", 1},
+ {"ʋ", 0},
+ {"P", 1},
+ {"Ƥ", 0},
+ {"M", 1},
+ {"Ɱ", 0},
+ {"O", 1},
+ {"Ỏ", 0},
+ {"abreve", 1},
+ {"ẳ", 0},
+ {"m", 1},
+ {"ɱ", 0},
+ {"r", 1},
+ {"ɼ", 0},
+ {"s", 1},
+ {"ʂ", 0},
+ {"Z", 1},
+ {"Ȥ", 0},
+ {"A", 1},
+ {"Ả", 0},
+ {"c", 1},
+ {"ƈ", 0},
+ {"T", 1},
+ {"Ƭ", 0},
+ {"dead_hook", 1},
+ {"̉", 0},
+ {"K", 1},
+ {"Ƙ", 0},
+ {"B", 1},
+ {"Ɓ", 0},
+ {"Uhorn", 1},
+ {"Ử", 0},
+ {"h", 1},
+ {"ɦ", 0},
+ {"I", 1},
+ {"Ỉ", 0},
+ {"N", 1},
+ {"Ɲ", 0},
+ {"U", 1},
+ {"Ủ", 0},
+ {"dead_belowbreve", 4},
+ {"H", 1},
+ {"Ḫ", 0},
+ {"h", 1},
+ {"ḫ", 0},
+ {"dead_cedilla", 73},
+ {"dead_breve", 4},
+ {"e", 1},
+ {"ḝ", 0},
+ {"E", 1},
+ {"Ḝ", 0},
+ {"g", 1},
+ {"ģ", 0},
+ {"dead_currency", 4},
+ {"C", 1},
+ {"₵", 0},
+ {"c", 1},
+ {"₵", 0},
+ {"C", 1},
+ {"Ç", 0},
+ {"e", 1},
+ {"ȩ", 0},
+ {"l", 1},
+ {"ļ", 0},
+ {"t", 1},
+ {"ţ", 0},
+ {"ColonSign", 1},
+ {"₵", 0},
+ {"space", 1},
+ {"¸", 0},
+ {"k", 1},
+ {"ķ", 0},
+ {"n", 1},
+ {"ņ", 0},
+ {"nobreakspace", 1},
+ {"̧", 0},
+ {"G", 1},
+ {"Ģ", 0},
+ {"H", 1},
+ {"Ḩ", 0},
+ {"E", 1},
+ {"Ȩ", 0},
+ {"S", 1},
+ {"Ş", 0},
+ {"Cacute", 1},
+ {"Ḉ", 0},
+ {"d", 1},
+ {"ḑ", 0},
+ {"D", 1},
+ {"Ḑ", 0},
+ {"cent", 1},
+ {"₵", 0},
+ {"cacute", 1},
+ {"ḉ", 0},
+ {"r", 1},
+ {"ŗ", 0},
+ {"s", 1},
+ {"ş", 0},
+ {"R", 1},
+ {"Ŗ", 0},
+ {"c", 1},
+ {"ç", 0},
+ {"L", 1},
+ {"Ļ", 0},
+ {"T", 1},
+ {"Ţ", 0},
+ {"K", 1},
+ {"Ķ", 0},
+ {"dead_cedilla", 1},
+ {"¸", 0},
+ {"dead_acute", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"h", 1},
+ {"ḩ", 0},
+ {"N", 1},
+ {"Ņ", 0},
+ {"dead_inverted_breve", 24},
+ {"a", 1},
+ {"ȃ", 0},
+ {"e", 1},
+ {"ȇ", 0},
+ {"o", 1},
+ {"ȏ", 0},
+ {"i", 1},
+ {"ȋ", 0},
+ {"u", 1},
+ {"ȗ", 0},
+ {"E", 1},
+ {"Ȇ", 0},
+ {"O", 1},
+ {"Ȏ", 0},
+ {"r", 1},
+ {"ȓ", 0},
+ {"A", 1},
+ {"Ȃ", 0},
+ {"R", 1},
+ {"Ȓ", 0},
+ {"I", 1},
+ {"Ȋ", 0},
+ {"U", 1},
+ {"Ȗ", 0},
+ {"dead_diaeresis", 190},
+ {"W", 1},
+ {"Ẅ", 0},
+ {"a", 1},
+ {"ä", 0},
+ {"Greek_IOTA", 1},
+ {"Ϊ", 0},
+ {"dead_grave", 4},
+ {"u", 1},
+ {"ǜ", 0},
+ {"U", 1},
+ {"Ǜ", 0},
+ {"Greek_iota", 1},
+ {"ϊ", 0},
+ {"Umacron", 1},
+ {"Ṻ", 0},
+ {"Cyrillic_ZE", 1},
+ {"Ӟ", 0},
+ {"dead_belowdiaeresis", 2},
+ {"equal", 1},
+ {"⩷", 0},
+ {"e", 1},
+ {"ë", 0},
+ {"o", 1},
+ {"ö", 0},
+ {"iacute", 1},
+ {"ḯ", 0},
+ {"Cyrillic_ze", 1},
+ {"ӟ", 0},
+ {"t", 1},
+ {"ẗ", 0},
+ {"Greek_upsilon", 1},
+ {"ϋ", 0},
+ {"space", 1},
+ {"\"", 0},
+ {"dead_macron", 12},
+ {"a", 1},
+ {"ǟ", 0},
+ {"o", 1},
+ {"ȫ", 0},
+ {"u", 1},
+ {"ṻ", 0},
+ {"O", 1},
+ {"Ȫ", 0},
+ {"A", 1},
+ {"Ǟ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"Cyrillic_I", 1},
+ {"Ӥ", 0},
+ {"y", 1},
+ {"ÿ", 0},
+ {"Multi_key", 15},
+ {"underscore", 4},
+ {"u", 1},
+ {"ṻ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"macron", 4},
+ {"u", 1},
+ {"ṻ", 0},
+ {"U", 1},
+ {"Ṻ", 0},
+ {"asciitilde", 4},
+ {"o", 1},
+ {"ṏ", 0},
+ {"O", 1},
+ {"Ṏ", 0},
+ {"Cyrillic_O", 1},
+ {"Ӧ", 0},
+ {"i", 1},
+ {"ï", 0},
+ {"Ukrainian_I", 1},
+ {"Ї", 0},
+ {"dead_caron", 4},
+ {"u", 1},
+ {"ǚ", 0},
+ {"U", 1},
+ {"Ǚ", 0},
+ {"dead_tilde", 4},
+ {"o", 1},
+ {"ṏ", 0},
+ {"O", 1},
+ {"Ṏ", 0},
+ {"Cyrillic_che", 1},
+ {"ӵ", 0},
+ {"Uacute", 1},
+ {"Ǘ", 0},
+ {"Cyrillic_a", 1},
+ {"ӓ", 0},
+ {"Ugrave", 1},
+ {"Ǜ", 0},
+ {"x", 1},
+ {"ẍ", 0},
+ {"amacron", 1},
+ {"ǟ", 0},
+ {"Cyrillic_U", 1},
+ {"Ӱ", 0},
+ {"nobreakspace", 1},
+ {"̈", 0},
+ {"omacron", 1},
+ {"ȫ", 0},
+ {"uacute", 1},
+ {"ǘ", 0},
+ {"u", 1},
+ {"ü", 0},
+ {"otilde", 1},
+ {"ṏ", 0},
+ {"Iacute", 1},
+ {"Ḯ", 0},
+ {"H", 1},
+ {"Ḧ", 0},
+ {"Cyrillic_YERU", 1},
+ {"Ӹ", 0},
+ {"Cyrillic_ie", 1},
+ {"ё", 0},
+ {"E", 1},
+ {"Ë", 0},
+ {"Y", 1},
+ {"Ÿ", 0},
+ {"Cyrillic_i", 1},
+ {"ӥ", 0},
+ {"Otilde", 1},
+ {"Ṏ", 0},
+ {"Cyrillic_zhe", 1},
+ {"ӝ", 0},
+ {"umacron", 1},
+ {"ṻ", 0},
+ {"Cyrillic_yeru", 1},
+ {"ӹ", 0},
+ {"acute", 1},
+ {"̈́", 0},
+ {"w", 1},
+ {"ẅ", 0},
+ {"Cyrillic_CHE", 1},
+ {"Ӵ", 0},
+ {"Cyrillic_o", 1},
+ {"ӧ", 0},
+ {"Ukrainian_i", 1},
+ {"ї", 0},
+ {"Cyrillic_E", 1},
+ {"Ӭ", 0},
+ {"apostrophe", 1},
+ {"̈́", 0},
+ {"O", 1},
+ {"Ö", 0},
+ {"A", 1},
+ {"Ä", 0},
+ {"Cyrillic_A", 1},
+ {"Ӓ", 0},
+ {"ugrave", 1},
+ {"ǜ", 0},
+ {"Omacron", 1},
+ {"Ȫ", 0},
+ {"Cyrillic_ZHE", 1},
+ {"Ӝ", 0},
+ {"Cyrillic_IE", 1},
+ {"Ё", 0},
+ {"dead_diaeresis", 1},
+ {"¨", 0},
+ {"Amacron", 1},
+ {"Ǟ", 0},
+ {"Cyrillic_e", 1},
+ {"ӭ", 0},
+ {"dead_acute", 14},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"space", 1},
+ {"΅", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"X", 1},
+ {"Ẍ", 0},
+ {"h", 1},
+ {"ḧ", 0},
+ {"I", 1},
+ {"Ï", 0},
+ {"U", 1},
+ {"Ü", 0},
+ {"Cyrillic_u", 1},
+ {"ӱ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ϋ", 0},
+ {"dead_acute", 500},
+ {"W", 1},
+ {"Ẃ", 0},
+ {"dead_breve", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"g", 1},
+ {"ǵ", 0},
+ {"a", 1},
+ {"á", 0},
+ {"Greek_IOTA", 1},
+ {"Ί", 0},
+ {"Greek_iota", 1},
+ {"ί", 0},
+ {"dead_horn", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"dead_circumflex", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ό", 0},
+ {"Acircumflex", 1},
+ {"Ấ", 0},
+ {"C", 1},
+ {"Ć", 0},
+ {"Cyrillic_er", 1},
+ {"р́", 0},
+ {"e", 1},
+ {"é", 0},
+ {"Utilde", 1},
+ {"Ṹ", 0},
+ {"o", 1},
+ {"ó", 0},
+ {"l", 1},
+ {"ĺ", 0},
+ {"Udiaeresis", 1},
+ {"Ǘ", 0},
+ {"Greek_upsilon", 1},
+ {"ύ", 0},
+ {"uhorn", 1},
+ {"ứ", 0},
+ {"space", 1},
+ {"'", 0},
+ {"dead_macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"acircumflex", 1},
+ {"ấ", 0},
+ {"Ecircumflex", 1},
+ {"Ế", 0},
+ {"Cyrillic_I", 1},
+ {"И́", 0},
+ {"y", 1},
+ {"ý", 0},
+ {"Multi_key", 153},
+ {"KP_Divide", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"o", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"b", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"parenright", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"quotedbl", 12},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"plus", 8},
+ {"o", 1},
+ {"ớ", 0},
+ {"u", 1},
+ {"ứ", 0},
+ {"O", 1},
+ {"Ớ", 0},
+ {"U", 1},
+ {"Ứ", 0},
+ {"cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"underscore", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"macron", 8},
+ {"e", 1},
+ {"ḗ", 0},
+ {"o", 1},
+ {"ṓ", 0},
+ {"E", 1},
+ {"Ḗ", 0},
+ {"O", 1},
+ {"Ṓ", 0},
+ {"comma", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"asciitilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"slash", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"parenleft", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"U", 4},
+ {"a", 1},
+ {"ắ", 0},
+ {"A", 1},
+ {"Ắ", 0},
+ {"asciicircum", 12},
+ {"a", 1},
+ {"ấ", 0},
+ {"e", 1},
+ {"ế", 0},
+ {"o", 1},
+ {"ố", 0},
+ {"E", 1},
+ {"Ế", 0},
+ {"O", 1},
+ {"Ố", 0},
+ {"A", 1},
+ {"Ấ", 0},
+ {"idiaeresis", 1},
+ {"ḯ", 0},
+ {"Cyrillic_O", 1},
+ {"О́", 0},
+ {"i", 1},
+ {"í", 0},
+ {"k", 1},
+ {"ḱ", 0},
+ {"n", 1},
+ {"ń", 0},
+ {"ccedilla", 1},
+ {"ḉ", 0},
+ {"Cyrillic_GHE", 1},
+ {"Ѓ", 0},
+ {"dead_tilde", 8},
+ {"o", 1},
+ {"ṍ", 0},
+ {"u", 1},
+ {"ṹ", 0},
+ {"O", 1},
+ {"Ṍ", 0},
+ {"U", 1},
+ {"Ṹ", 0},
+ {"Cyrillic_a", 1},
+ {"а́", 0},
+ {"Ohorn", 1},
+ {"Ớ", 0},
+ {"ohorn", 1},
+ {"ớ", 0},
+ {"sabovedot", 1},
+ {"ṥ", 0},
+ {"Cyrillic_ER", 1},
+ {"Р́", 0},
+ {"Greek_epsilon", 1},
+ {"έ", 0},
+ {"Cyrillic_KA", 1},
+ {"Ќ", 0},
+ {"Cyrillic_U", 1},
+ {"У́", 0},
+ {"dead_abovering", 4},
+ {"a", 1},
+ {"ǻ", 0},
+ {"A", 1},
+ {"Ǻ", 0},
+ {"nobreakspace", 1},
+ {"́", 0},
+ {"V", 1},
+ {"Ǘ", 0},
+ {"Ocircumflex", 1},
+ {"Ố", 0},
+ {"AE", 1},
+ {"Ǽ", 0},
+ {"omacron", 1},
+ {"ṓ", 0},
+ {"ocircumflex", 1},
+ {"ố", 0},
+ {"u", 1},
+ {"ú", 0},
+ {"z", 1},
+ {"ź", 0},
+ {"G", 1},
+ {"Ǵ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ά", 0},
+ {"otilde", 1},
+ {"ṍ", 0},
+ {"utilde", 1},
+ {"ṹ", 0},
+ {"Cyrillic_ie", 1},
+ {"е́", 0},
+ {"emacron", 1},
+ {"ḗ", 0},
+ {"E", 1},
+ {"É", 0},
+ {"S", 1},
+ {"Ś", 0},
+ {"Greek_iotadieresis", 1},
+ {"ΐ", 0},
+ {"Y", 1},
+ {"Ý", 0},
+ {"Cyrillic_i", 1},
+ {"и́", 0},
+ {"dead_dasia", 28},
+ {"Greek_IOTA", 1},
+ {"Ἵ", 0},
+ {"Greek_iota", 1},
+ {"ἵ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὅ", 0},
+ {"Greek_upsilon", 1},
+ {"ὕ", 0},
+ {"Greek_epsilon", 1},
+ {"ἕ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἅ", 0},
+ {"Greek_omicron", 1},
+ {"ὅ", 0},
+ {"Greek_eta", 1},
+ {"ἥ", 0},
+ {"Greek_alpha", 1},
+ {"ἅ", 0},
+ {"Greek_ETA", 1},
+ {"Ἥ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἕ", 0},
+ {"Greek_omega", 1},
+ {"ὥ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὥ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ὕ", 0},
+ {"Greek_upsilondieresis", 1},
+ {"ΰ", 0},
+ {"Greek_omicron", 1},
+ {"ό", 0},
+ {"Greek_eta", 1},
+ {"ή", 0},
+ {"Otilde", 1},
+ {"Ṍ", 0},
+ {"Cyrillic_ka", 1},
+ {"ќ", 0},
+ {"Aring", 1},
+ {"Ǻ", 0},
+ {"Abreve", 1},
+ {"Ắ", 0},
+ {"dead_psili", 26},
+ {"Greek_IOTA", 1},
+ {"Ἴ", 0},
+ {"Greek_iota", 1},
+ {"ἴ", 0},
+ {"Greek_OMICRON", 1},
+ {"Ὄ", 0},
+ {"Greek_upsilon", 1},
+ {"ὔ", 0},
+ {"Greek_epsilon", 1},
+ {"ἔ", 0},
+ {"Greek_ALPHA", 1},
+ {"Ἄ", 0},
+ {"Greek_omicron", 1},
+ {"ὄ", 0},
+ {"Greek_eta", 1},
+ {"ἤ", 0},
+ {"Greek_alpha", 1},
+ {"ἄ", 0},
+ {"Greek_ETA", 1},
+ {"Ἤ", 0},
+ {"Greek_EPSILON", 1},
+ {"Ἔ", 0},
+ {"Greek_omega", 1},
+ {"ὤ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ὤ", 0},
+ {"Greek_alpha", 1},
+ {"ά", 0},
+ {"ecircumflex", 1},
+ {"ế", 0},
+ {"dead_abovedot", 4},
+ {"S", 1},
+ {"Ṥ", 0},
+ {"s", 1},
+ {"ṥ", 0},
+ {"w", 1},
+ {"ẃ", 0},
+ {"Greek_ETA", 1},
+ {"Ή", 0},
+ {"Cyrillic_o", 1},
+ {"о́", 0},
+ {"Emacron", 1},
+ {"Ḗ", 0},
+ {"Ooblique", 1},
+ {"Ǿ", 0},
+ {"p", 1},
+ {"ṕ", 0},
+ {"v", 1},
+ {"ǘ", 0},
+ {"P", 1},
+ {"Ṕ", 0},
+ {"M", 1},
+ {"Ḿ", 0},
+ {"O", 1},
+ {"Ó", 0},
+ {"abreve", 1},
+ {"ắ", 0},
+ {"m", 1},
+ {"ḿ", 0},
+ {"r", 1},
+ {"ŕ", 0},
+ {"s", 1},
+ {"ś", 0},
+ {"Z", 1},
+ {"Ź", 0},
+ {"dead_stroke", 4},
+ {"o", 1},
+ {"ǿ", 0},
+ {"O", 1},
+ {"Ǿ", 0},
+ {"A", 1},
+ {"Á", 0},
+ {"R", 1},
+ {"Ŕ", 0},
+ {"c", 1},
+ {"ć", 0},
+ {"Idiaeresis", 1},
+ {"Ḯ", 0},
+ {"L", 1},
+ {"Ĺ", 0},
+ {"Greek_EPSILON", 1},
+ {"Έ", 0},
+ {"Cyrillic_A", 1},
+ {"А́", 0},
+ {"Ccedilla", 1},
+ {"Ḉ", 0},
+ {"aring", 1},
+ {"ǻ", 0},
+ {"K", 1},
+ {"Ḱ", 0},
+ {"Omacron", 1},
+ {"Ṓ", 0},
+ {"Cyrillic_IE", 1},
+ {"Е́", 0},
+ {"Sabovedot", 1},
+ {"Ṥ", 0},
+ {"dead_cedilla", 4},
+ {"C", 1},
+ {"Ḉ", 0},
+ {"c", 1},
+ {"ḉ", 0},
+ {"Greek_omega", 1},
+ {"ώ", 0},
+ {"dead_diaeresis", 14},
+ {"Greek_iota", 1},
+ {"ΐ", 0},
+ {"Greek_upsilon", 1},
+ {"ΰ", 0},
+ {"space", 1},
+ {"΅", 0},
+ {"i", 1},
+ {"ḯ", 0},
+ {"u", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Ḯ", 0},
+ {"U", 1},
+ {"Ǘ", 0},
+ {"Uhorn", 1},
+ {"Ứ", 0},
+ {"Greek_OMEGA", 1},
+ {"Ώ", 0},
+ {"dead_acute", 1},
+ {"´", 0},
+ {"oslash", 1},
+ {"ǿ", 0},
+ {"Cyrillic_ghe", 1},
+ {"ѓ", 0},
+ {"udiaeresis", 1},
+ {"ǘ", 0},
+ {"I", 1},
+ {"Í", 0},
+ {"N", 1},
+ {"Ń", 0},
+ {"U", 1},
+ {"Ú", 0},
+ {"Cyrillic_u", 1},
+ {"у́", 0},
+ {"ae", 1},
+ {"ǽ", 0},
+ {"Greek_UPSILON", 1},
+ {"Ύ", 0},
+ {"dead_belowmacron", 34},
+ {"l", 1},
+ {"ḻ", 0},
+ {"t", 1},
+ {"ṯ", 0},
+ {"b", 1},
+ {"ḇ", 0},
+ {"k", 1},
+ {"ḵ", 0},
+ {"n", 1},
+ {"ṉ", 0},
+ {"z", 1},
+ {"ẕ", 0},
+ {"d", 1},
+ {"ḏ", 0},
+ {"D", 1},
+ {"Ḏ", 0},
+ {"r", 1},
+ {"ṟ", 0},
+ {"Z", 1},
+ {"Ẕ", 0},
+ {"R", 1},
+ {"Ṟ", 0},
+ {"L", 1},
+ {"Ḻ", 0},
+ {"T", 1},
+ {"Ṯ", 0},
+ {"K", 1},
+ {"Ḵ", 0},
+ {"B", 1},
+ {"Ḇ", 0},
+ {"h", 1},
+ {"ẖ", 0},
+ {"N", 1},
+ {"Ṉ", 0},
+ {"dead_belowring", 6},
+ {"a", 1},
+ {"ḁ", 0},
+ {"bar", 1},
+ {"⫰", 0},
+ {"A", 1},
+ {"Ḁ", 0},
+ {NULL, 0},
+};
diff --git a/src/lib/ecore_input/ecore_input_evas.c b/src/lib/ecore_input/ecore_input_evas.c
new file mode 100644
index 0000000000..1f5b38e03c
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input_evas.c
@@ -0,0 +1,418 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "Ecore_Input.h"
+
+#include "Ecore_Input_Evas.h"
+#include "ecore_input_evas_private.h"
+
+int _ecore_input_evas_log_dom = -1;
+
+typedef struct _Ecore_Input_Window Ecore_Input_Window;
+struct _Ecore_Input_Window
+{
+ Evas *evas;
+ void *window;
+ Ecore_Event_Mouse_Move_Cb move_mouse;
+ Ecore_Event_Multi_Move_Cb move_multi;
+ Ecore_Event_Multi_Down_Cb down_multi;
+ Ecore_Event_Multi_Up_Cb up_multi;
+ int ignore_event;
+};
+
+static int _ecore_event_evas_init_count = 0;
+static Ecore_Event_Handler *ecore_event_evas_handlers[8];
+static Eina_Hash *_window_hash = NULL;
+
+EAPI void
+ecore_event_evas_modifier_lock_update(Evas *e, unsigned int modifiers)
+{
+ if (modifiers & ECORE_EVENT_MODIFIER_SHIFT)
+ evas_key_modifier_on(e, "Shift");
+ else evas_key_modifier_off(e, "Shift");
+
+ if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
+ evas_key_modifier_on(e, "Control");
+ else evas_key_modifier_off(e, "Control");
+
+ if (modifiers & ECORE_EVENT_MODIFIER_ALT)
+ evas_key_modifier_on(e, "Alt");
+ else evas_key_modifier_off(e, "Alt");
+
+ if (modifiers & ECORE_EVENT_MODIFIER_WIN)
+ {
+ evas_key_modifier_on(e, "Super");
+ evas_key_modifier_on(e, "Hyper");
+ }
+ else
+ {
+ evas_key_modifier_off(e, "Super");
+ evas_key_modifier_off(e, "Hyper");
+ }
+
+ if (modifiers & ECORE_EVENT_MODIFIER_ALTGR)
+ evas_key_modifier_on(e, "AltGr");
+ else evas_key_modifier_off(e, "AltGr");
+
+ if (modifiers & ECORE_EVENT_LOCK_SCROLL)
+ evas_key_lock_on(e, "Scroll_Lock");
+ else evas_key_lock_off(e, "Scroll_Lock");
+
+ if (modifiers & ECORE_EVENT_LOCK_NUM)
+ evas_key_lock_on(e, "Num_Lock");
+ else evas_key_lock_off(e, "Num_Lock");
+
+ if (modifiers & ECORE_EVENT_LOCK_CAPS)
+ evas_key_lock_on(e, "Caps_Lock");
+ else evas_key_lock_off(e, "Caps_Lock");
+
+ if (modifiers & ECORE_EVENT_LOCK_SHIFT)
+ evas_key_lock_on(e, "Shift_Lock");
+ else evas_key_lock_off(e, "Shift_Lock");
+}
+
+EAPI void
+ecore_event_window_register(Ecore_Window id, void *window, Evas *evas,
+ Ecore_Event_Mouse_Move_Cb move_mouse,
+ Ecore_Event_Multi_Move_Cb move_multi,
+ Ecore_Event_Multi_Down_Cb down_multi,
+ Ecore_Event_Multi_Up_Cb up_multi)
+{
+ Ecore_Input_Window *w;
+
+ w = calloc(1, sizeof(Ecore_Input_Window));
+ if (!w) return;
+
+ w->evas = evas;
+ w->window = window;
+ w->move_mouse = move_mouse;
+ w->move_multi = move_multi;
+ w->down_multi = down_multi;
+ w->up_multi = up_multi;
+ w->ignore_event = 0;
+
+ eina_hash_add(_window_hash, &id, w);
+
+ evas_key_modifier_add(evas, "Shift");
+ evas_key_modifier_add(evas, "Control");
+ evas_key_modifier_add(evas, "Alt");
+ evas_key_modifier_add(evas, "Meta");
+ evas_key_modifier_add(evas, "Hyper");
+ evas_key_modifier_add(evas, "Super");
+ evas_key_modifier_add(evas, "AltGr");
+ evas_key_lock_add(evas, "Caps_Lock");
+ evas_key_lock_add(evas, "Num_Lock");
+ evas_key_lock_add(evas, "Scroll_Lock");
+}
+
+EAPI void
+ecore_event_window_unregister(Ecore_Window id)
+{
+ eina_hash_del(_window_hash, &id, NULL);
+}
+
+EAPI void *
+ecore_event_window_match(Ecore_Window id)
+{
+ Ecore_Input_Window *lookup;
+
+ lookup = eina_hash_find(_window_hash, &id);
+ if (lookup) return lookup->window;
+ return NULL;
+}
+
+EAPI void
+ecore_event_window_ignore_events(Ecore_Window id, int ignore_event)
+{
+ Ecore_Input_Window *lookup;
+
+ lookup = eina_hash_find(_window_hash, &id);
+ if (!lookup) return;
+ lookup->ignore_event = ignore_event;
+}
+
+static Ecore_Input_Window*
+_ecore_event_window_match(Ecore_Window id)
+{
+ Ecore_Input_Window *lookup;
+
+ lookup = eina_hash_find(_window_hash, &id);
+ if (!lookup) return NULL;
+ if (lookup->ignore_event) return NULL; /* Pass on event. */
+ return lookup;
+}
+
+static Eina_Bool
+_ecore_event_evas_key(Ecore_Event_Key *e, Ecore_Event_Press press)
+{
+ Ecore_Input_Window *lookup;
+
+ lookup = _ecore_event_window_match(e->event_window);
+ if (!lookup) return ECORE_CALLBACK_PASS_ON;
+ ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
+ if (press == ECORE_DOWN)
+ evas_event_feed_key_down(lookup->evas, e->keyname, e->key, e->string, e->compose, e->timestamp, NULL);
+ else
+ evas_event_feed_key_up(lookup->evas, e->keyname, e->key, e->string, e->compose, e->timestamp, NULL);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_ecore_event_evas_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Press press)
+{
+ Ecore_Input_Window *lookup;
+ Evas_Button_Flags flags = EVAS_BUTTON_NONE;
+
+ lookup = _ecore_event_window_match(e->event_window);
+ if (!lookup) return ECORE_CALLBACK_PASS_ON;
+ if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK;
+ if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK;
+ if (e->multi.device == 0)
+ {
+ ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
+ if (press == ECORE_DOWN)
+ evas_event_feed_mouse_down(lookup->evas, e->buttons, flags,
+ e->timestamp, NULL);
+ else
+ evas_event_feed_mouse_up(lookup->evas, e->buttons, flags,
+ e->timestamp, NULL);
+ }
+ else
+ {
+ if (press == ECORE_DOWN)
+ {
+ if (lookup->down_multi)
+ lookup->down_multi(lookup->window, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, flags,
+ e->timestamp);
+ else
+ evas_event_feed_multi_down(lookup->evas, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, flags,
+ e->timestamp, NULL);
+ }
+ else
+ {
+ if (lookup->up_multi)
+ lookup->up_multi(lookup->window, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, flags,
+ e->timestamp);
+ else
+ evas_event_feed_multi_up(lookup->evas, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, flags,
+ e->timestamp, NULL);
+ }
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Event_Mouse_Move *e;
+ Ecore_Input_Window *lookup;
+
+ e = event;
+ lookup = _ecore_event_window_match(e->event_window);
+ if (!lookup) return ECORE_CALLBACK_PASS_ON;
+ if (e->multi.device == 0)
+ {
+ ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
+ if (lookup->move_mouse)
+ lookup->move_mouse(lookup->window, e->x, e->y, e->timestamp);
+ else
+ evas_event_feed_mouse_move(lookup->evas, e->x, e->y, e->timestamp,
+ NULL);
+ }
+ else
+ {
+ if (lookup->move_multi)
+ lookup->move_multi(lookup->window, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, e->timestamp);
+ else
+ evas_event_feed_multi_move(lookup->evas, e->multi.device,
+ e->x, e->y, e->multi.radius,
+ e->multi.radius_x, e->multi.radius_y,
+ e->multi.pressure, e->multi.angle,
+ e->multi.x, e->multi.y, e->timestamp,
+ NULL);
+ }
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_button_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_mouse_button((Ecore_Event_Mouse_Button *)event, ECORE_DOWN);
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_button_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_mouse_button((Ecore_Event_Mouse_Button *)event, ECORE_UP);
+}
+
+static Eina_Bool
+_ecore_event_evas_mouse_io(Ecore_Event_Mouse_IO *e, Ecore_Event_IO io)
+{
+ Ecore_Input_Window *lookup;
+
+ lookup = _ecore_event_window_match(e->event_window);
+ if (!lookup) return ECORE_CALLBACK_PASS_ON;
+ ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
+ switch (io)
+ {
+ case ECORE_IN:
+ evas_event_feed_mouse_in(lookup->evas, e->timestamp, NULL);
+ break;
+ case ECORE_OUT:
+ evas_event_feed_mouse_out(lookup->evas, e->timestamp, NULL);
+ break;
+ default:
+ break;
+ }
+
+ lookup->move_mouse(lookup->window, e->x, e->y, e->timestamp);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+EAPI Eina_Bool
+ecore_event_evas_key_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_key((Ecore_Event_Key *)event, ECORE_DOWN);
+}
+
+EAPI Eina_Bool
+ecore_event_evas_key_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_key((Ecore_Event_Key *)event, ECORE_UP);
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Event_Mouse_Wheel *e;
+ Ecore_Input_Window *lookup;
+
+ e = event;
+ lookup = _ecore_event_window_match(e->event_window);
+ if (!lookup) return ECORE_CALLBACK_PASS_ON;
+ ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
+ evas_event_feed_mouse_wheel(lookup->evas, e->direction, e->z, e->timestamp, NULL);
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_mouse_io((Ecore_Event_Mouse_IO *)event, ECORE_IN);
+}
+
+EAPI Eina_Bool
+ecore_event_evas_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ return _ecore_event_evas_mouse_io((Ecore_Event_Mouse_IO *)event, ECORE_OUT);
+}
+
+EAPI int
+ecore_event_evas_init(void)
+{
+ if (++_ecore_event_evas_init_count != 1)
+ return _ecore_event_evas_init_count;
+
+ _ecore_input_evas_log_dom = eina_log_domain_register
+ ("ecore_input_evas", ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR);
+ if (_ecore_input_evas_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the ecore input evas_module.");
+ return --_ecore_event_evas_init_count;
+ }
+
+ if (!ecore_init())
+ {
+ return --_ecore_event_evas_init_count;
+ }
+
+ if (!ecore_event_init())
+ {
+ goto shutdown_ecore;
+ }
+
+ ecore_event_evas_handlers[0] = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
+ ecore_event_evas_key_down,
+ NULL);
+ ecore_event_evas_handlers[1] = ecore_event_handler_add(ECORE_EVENT_KEY_UP,
+ ecore_event_evas_key_up,
+ NULL);
+ ecore_event_evas_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ ecore_event_evas_mouse_button_down,
+ NULL);
+ ecore_event_evas_handlers[3] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
+ ecore_event_evas_mouse_button_up,
+ NULL);
+ ecore_event_evas_handlers[4] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
+ ecore_event_evas_mouse_move,
+ NULL);
+ ecore_event_evas_handlers[5] = ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
+ ecore_event_evas_mouse_wheel,
+ NULL);
+ ecore_event_evas_handlers[6] = ecore_event_handler_add(ECORE_EVENT_MOUSE_IN,
+ ecore_event_evas_mouse_in,
+ NULL);
+ ecore_event_evas_handlers[7] = ecore_event_handler_add(ECORE_EVENT_MOUSE_OUT,
+ ecore_event_evas_mouse_out,
+ NULL);
+
+ _window_hash = eina_hash_pointer_new(free);
+
+ return _ecore_event_evas_init_count;
+
+ shutdown_ecore:
+ ecore_shutdown();
+
+ return --_ecore_event_evas_init_count;
+}
+
+EAPI int
+ecore_event_evas_shutdown(void)
+{
+ size_t i;
+
+ if (--_ecore_event_evas_init_count != 0)
+ return _ecore_event_evas_init_count;
+
+ eina_hash_free(_window_hash);
+ _window_hash = NULL;
+ for (i = 0; i < sizeof(ecore_event_evas_handlers) / sizeof(Ecore_Event_Handler *); i++)
+ {
+ ecore_event_handler_del(ecore_event_evas_handlers[i]);
+ ecore_event_evas_handlers[i] = NULL;
+ }
+
+ ecore_event_shutdown();
+ ecore_shutdown();
+
+ eina_log_domain_unregister(_ecore_input_evas_log_dom);
+ _ecore_input_evas_log_dom = -1;
+
+ return _ecore_event_evas_init_count;
+}
diff --git a/src/lib/ecore_input/ecore_input_evas_private.h b/src/lib/ecore_input/ecore_input_evas_private.h
new file mode 100644
index 0000000000..c19cfbf675
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input_evas_private.h
@@ -0,0 +1,37 @@
+#ifndef _ECORE_INPUT_PRIVATE_H
+#define _ECORE_INPUT_PRIVATE_H
+
+extern int _ecore_input_evas_log_dom;
+
+#ifdef ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR
+#undef ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR
+#endif
+
+#define ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_input_evas_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_input_evas_log_dom, __VA_ARGS__)
+
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_input_evas_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_input_evas_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+#undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_input_evas_log_dom, __VA_ARGS__)
+
+#endif
diff --git a/src/lib/ecore_input/ecore_input_private.h b/src/lib/ecore_input/ecore_input_private.h
new file mode 100644
index 0000000000..5660a2024a
--- /dev/null
+++ b/src/lib/ecore_input/ecore_input_private.h
@@ -0,0 +1,37 @@
+#ifndef _ECORE_INPUT_PRIVATE_H
+#define _ECORE_INPUT_PRIVATE_H
+
+extern int _ecore_input_log_dom;
+
+#ifdef ECORE_INPUT_DEFAULT_LOG_COLOR
+# undef ECORE_INPUT_DEFAULT_LOG_COLOR
+#endif
+
+#define ECORE_INPUT_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_input_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_input_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_input_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_input_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_input_log_dom, __VA_ARGS__)
+
+#endif
diff --git a/src/lib/ecore_ipc/Ecore_Ipc.h b/src/lib/ecore_ipc/Ecore_Ipc.h
new file mode 100644
index 0000000000..f77870f84d
--- /dev/null
+++ b/src/lib/ecore_ipc/Ecore_Ipc.h
@@ -0,0 +1,328 @@
+#ifndef _ECORE_IPC_H
+#define _ECORE_IPC_H
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_IPC_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif
+# else
+# define EAPI __declspec(dllimport)
+# endif
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif
+
+/**
+ * @file Ecore_Ipc.h
+ * @brief Ecore inter-process communication functions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _Ecore_Ipc_Server Ecore_Ipc_Server; /**< An IPC connection handle */
+typedef struct _Ecore_Ipc_Client Ecore_Ipc_Client; /**< An IPC connection handle */
+
+EAPI unsigned short _ecore_ipc_swap_16(unsigned short v);
+EAPI unsigned int _ecore_ipc_swap_32(unsigned int v);
+EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v);
+
+#ifdef WORDS_BIGENDIAN
+#define ECORE_IPC_SWAP2NET64(x) _ecore_ipc_swap_64(x)
+#define ECORE_IPC_SWAP2CPU64(x) _ecore_ipc_swap_64(x)
+#define ECORE_IPC_SWAP2NET32(x) _ecore_ipc_swap_32(x)
+#define ECORE_IPC_SWAP2CPU32(x) _ecore_ipc_swap_32(x)
+#define ECORE_IPC_SWAP2NET16(x) _ecore_ipc_swap_16(x)
+#define ECORE_IPC_SWAP2CPU16(x) _ecore_ipc_swap_16(x)
+#define ECORE_IPC_SWAP2NET8(x) (x)
+#define ECORE_IPC_SWAP2CPU8(x) (x)
+#else
+#define ECORE_IPC_SWAP2NET64(x) (x)
+#define ECORE_IPC_SWAP2CPU64(x) (x)
+#define ECORE_IPC_SWAP2NET32(x) (x)
+#define ECORE_IPC_SWAP2CPU32(x) (x)
+#define ECORE_IPC_SWAP2NET16(x) (x)
+#define ECORE_IPC_SWAP2CPU16(x) (x)
+#define ECORE_IPC_SWAP2NET8(x) (x)
+#define ECORE_IPC_SWAP2CPU8(x) (x)
+#endif
+
+/* 1, 2, 4 and 8 byte datatypes */
+/* unpacking */
+#define ECORE_IPC_GET64(v)\
+ { \
+ p->v = ECORE_IPC_SWAP2CPU64(*(long long *)(ptr)); \
+ ptr += 8; \
+ }
+#define ECORE_IPC_GET32(v)\
+ { \
+ p->v = ECORE_IPC_SWAP2CPU32(*(int *)(ptr)); \
+ ptr += 4; \
+ }
+#define ECORE_IPC_GET16(v)\
+ { \
+ p->v = ECORE_IPC_SWAP2CPU16(*(short *)(ptr)); \
+ ptr += 2; \
+ }
+#define ECORE_IPC_GET8(v) \
+ { \
+ p->v = ECORE_IPC_SWAP2CPU8(*(char *)(ptr)); \
+ ptr += 1; \
+ }
+/* packing */
+#define ECORE_IPC_PUT64(v)\
+ { \
+ *(long long *)(ptr) = ECORE_IPC_SWAP2NET64(p->v); \
+ ptr += 8; \
+ }
+#define ECORE_IPC_PUT32(v)\
+ { \
+ *(int *)(ptr) = ECORE_IPC_SWAP2NET32(p->v); \
+ ptr += 4; \
+ }
+#define ECORE_IPC_PUT16(v)\
+ { \
+ *(short *)(ptr) = ECORE_IPC_SWAP2NET16(p->v); \
+ ptr += 2; \
+ }
+#define ECORE_IPC_PUT8(v) \
+ { \
+ *(char *)(ptr) = ECORE_IPC_SWAP2NET8(p->v); \
+ ptr += 1; \
+ }
+/* padding data */
+#define ECORE_IPC_PAD8() ptr += 1
+#define ECORE_IPC_PAD16() ptr += 2
+#define ECORE_IPC_PAD32() ptr += 4
+#define ECORE_IPC_PAD64() ptr += 8
+
+/* counting data when encoding lists */
+#define ECORE_IPC_CNT8() len += 1
+#define ECORE_IPC_CNT16() len += 2
+#define ECORE_IPC_CNT32() len += 4
+#define ECORE_IPC_CNT64() len += 8
+
+/* strings */
+#define ECORE_IPC_CHEKS() if (*((unsigned char *)d + s - 1) != 0) return 0;
+#define ECORE_IPC_GETS(v) \
+ { \
+ if (ptr < ((unsigned char *)d + s)) \
+ { \
+ p->v = (char *)ptr; \
+ ptr += strlen(p->v) + 1; \
+ } \
+ }
+#define ECORE_IPC_PUTS(v, l)\
+ { \
+ strcpy((char *)ptr, p->v); \
+ ptr += l + 1; \
+ }
+
+/* handy to calculate what sized block we need to alloc */
+#define ECORE_IPC_SLEN(l, v) ((l = strlen(p->v)) + 1)
+#define ECORE_IPC_CNTS(v) len += strlen(p->v) + 1
+
+/* saves typing function headers */
+#define ECORE_IPC_DEC_STRUCT_PROTO(x) static int x(void *d, int s, void *pp)
+#define ECORE_IPC_ENC_STRUCT_PROTO(x) static void *x(void *pp, int *s)
+#define ECORE_IPC_DEC_EINA_LIST_PROTO(x) static Eina_List *x(void *d, int s)
+#define ECORE_IPC_ENC_EINA_LIST_PROTO(x) static void *x(Eina_List *lp, int *s)
+
+
+/* decoder setup - saves typing. requires data packet of exact size, or fail */
+#define ECORE_IPC_DEC_STRUCT_HEAD_EXACT(typ, x) \
+ typ *p; \
+ unsigned char *ptr; \
+ p = (typ *)pp; \
+ if (!d) return 0; if (s != (x)) return 0; \
+ ptr = d;
+/* decoder setup - saves typing. requires data packet of a minimum size */
+#define ECORE_IPC_DEC_STRUCT_HEAD_MIN(typ, x) \
+ typ *p; \
+ unsigned char *ptr; \
+ p = (typ *)pp; \
+ if (!d) return 0; if (s < (x)) return 0; \
+ ptr = d;
+/* footer for the hell of it */
+#define ECORE_IPC_DEC_STRUCT_FOOT() return 1
+/* header for encoder - gives native strct type and size of flattened packet */
+#define ECORE_IPC_ENC_STRUCT_HEAD(typ, sz) \
+ typ *p; \
+ unsigned char *d, *ptr; \
+ int len; \
+ *s = 0; \
+ if(!pp) return NULL; \
+ p = (typ *)pp; \
+ len = sz; \
+ d = malloc(len); \
+ if (!d) return NULL; \
+ *s = len; \
+ ptr = d;
+/* footer for the hell of it */
+#define ECORE_IPC_ENC_STRUCT_FOOT() return d
+
+#define ECORE_IPC_DEC_EINA_LIST_HEAD(typ) \
+ unsigned char *ptr; \
+ Eina_List *l; \
+ typ *p; \
+ l = NULL; \
+ ptr = d; \
+ while(ptr < (unsigned char *)(d + s)) \
+ { \
+ p = malloc(sizeof(typ));
+
+#define ECORE_IPC_DEC_EINA_LIST_FOOT() \
+ l = eina_list_append(l, p); \
+ } \
+ return l
+#define ECORE_IPC_ENC_EINA_LIST_HEAD_START(typ) \
+ Eina_List *l; \
+ typ *p; \
+ unsigned char *d, *ptr; \
+ int len; \
+ *s = 0; \
+ len = 0; \
+ for (l = lp; l; l = l->next) \
+ { \
+ p = l->data;
+#define ECORE_IPC_ENC_EINA_LIST_HEAD_FINISH() \
+ } \
+ d = malloc(len); \
+ if(!d) return NULL; \
+ *s = len; \
+ ptr = d; \
+ for (l = lp; l; l = l->next) \
+ { \
+ p = l->data;
+
+#define ECORE_IPC_ENC_EINA_LIST_FOOT() \
+ } \
+ return d
+
+typedef enum _Ecore_Ipc_Type
+{
+ ECORE_IPC_LOCAL_USER,
+ ECORE_IPC_LOCAL_SYSTEM,
+ ECORE_IPC_REMOTE_SYSTEM,
+ ECORE_IPC_USE_SSL = (1 << 4),
+ ECORE_IPC_NO_PROXY = (1 << 5)
+} Ecore_Ipc_Type;
+
+typedef struct _Ecore_Ipc_Event_Client_Add Ecore_Ipc_Event_Client_Add;
+typedef struct _Ecore_Ipc_Event_Client_Del Ecore_Ipc_Event_Client_Del;
+typedef struct _Ecore_Ipc_Event_Server_Add Ecore_Ipc_Event_Server_Add;
+typedef struct _Ecore_Ipc_Event_Server_Del Ecore_Ipc_Event_Server_Del;
+typedef struct _Ecore_Ipc_Event_Client_Data Ecore_Ipc_Event_Client_Data;
+typedef struct _Ecore_Ipc_Event_Server_Data Ecore_Ipc_Event_Server_Data;
+
+struct _Ecore_Ipc_Event_Client_Add
+{
+ Ecore_Ipc_Client *client;
+};
+
+struct _Ecore_Ipc_Event_Client_Del
+{
+ Ecore_Ipc_Client *client;
+};
+
+struct _Ecore_Ipc_Event_Server_Add
+{
+ Ecore_Ipc_Server *server;
+};
+
+struct _Ecore_Ipc_Event_Server_Del
+{
+ Ecore_Ipc_Server *server;
+};
+
+struct _Ecore_Ipc_Event_Client_Data
+{
+ Ecore_Ipc_Client *client;
+ /* FIXME: this needs to become an ipc message */
+ int major;
+ int minor;
+ int ref;
+ int ref_to;
+ int response;
+ void *data;
+ int size;
+};
+
+struct _Ecore_Ipc_Event_Server_Data
+{
+ Ecore_Ipc_Server *server;
+ /* FIXME: this needs to become an ipc message */
+ int major;
+ int minor;
+ int ref;
+ int ref_to;
+ int response;
+ void *data;
+ int size;
+};
+
+EAPI extern int ECORE_IPC_EVENT_CLIENT_ADD;
+EAPI extern int ECORE_IPC_EVENT_CLIENT_DEL;
+EAPI extern int ECORE_IPC_EVENT_SERVER_ADD;
+EAPI extern int ECORE_IPC_EVENT_SERVER_DEL;
+EAPI extern int ECORE_IPC_EVENT_CLIENT_DATA;
+EAPI extern int ECORE_IPC_EVENT_SERVER_DATA;
+
+EAPI int ecore_ipc_init(void);
+EAPI int ecore_ipc_shutdown(void);
+
+/* FIXME: need to add protocol type parameter */
+EAPI Ecore_Ipc_Server *ecore_ipc_server_add(Ecore_Ipc_Type type, const char *name, int port, const void *data);
+
+/* FIXME: need to add protocol type parameter */
+EAPI Ecore_Ipc_Server *ecore_ipc_server_connect(Ecore_Ipc_Type type, char *name, int port, const void *data);
+EAPI void *ecore_ipc_server_del(Ecore_Ipc_Server *svr);
+EAPI void *ecore_ipc_server_data_get(Ecore_Ipc_Server *svr);
+EAPI Eina_Bool ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr);
+EAPI Eina_List *ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr);
+/* FIXME: this needs to become an ipc message */
+EAPI int ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int ref_to, int response, const void *data, int size);
+EAPI void ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char reject_excess_clients);
+EAPI void ecore_ipc_server_data_size_max_set(Ecore_Ipc_Server *srv, int size);
+EAPI int ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *srv);
+EAPI const char *ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr);
+EAPI void ecore_ipc_server_flush(Ecore_Ipc_Server *svr);
+
+/* FIXME: this needs to become an ipc message */
+EAPI int ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int ref_to, int response, const void *data, int size);
+EAPI Ecore_Ipc_Server *ecore_ipc_client_server_get(Ecore_Ipc_Client *cl);
+EAPI void *ecore_ipc_client_del(Ecore_Ipc_Client *cl);
+EAPI void ecore_ipc_client_data_set(Ecore_Ipc_Client *cl, const void *data);
+EAPI void *ecore_ipc_client_data_get(Ecore_Ipc_Client *cl);
+EAPI void ecore_ipc_client_data_size_max_set(Ecore_Ipc_Client *cl, int size);
+EAPI int ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl);
+EAPI const char *ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl);
+EAPI void ecore_ipc_client_flush(Ecore_Ipc_Client *cl);
+
+EAPI int ecore_ipc_ssl_available_get(void);
+/* FIXME: need to add a callback to "ok" large ipc messages greater than */
+/* a certain size (seurity/DOS attack safety) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_ipc/ecore_ipc.c b/src/lib/ecore_ipc/ecore_ipc.c
new file mode 100644
index 0000000000..a421febdf9
--- /dev/null
+++ b/src/lib/ecore_ipc/ecore_ipc.c
@@ -0,0 +1,1599 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <sys/types.h>
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#include <Ecore.h>
+#include <ecore_private.h>
+#include <Ecore_Con.h>
+
+#include "Ecore_Ipc.h"
+#include "ecore_ipc_private.h"
+
+#define DLT_ZERO 0
+#define DLT_ONE 1
+#define DLT_SAME 2
+#define DLT_SHL 3
+#define DLT_SHR 4
+#define DLT_ADD8 5
+#define DLT_DEL8 6
+#define DLT_ADDU8 7
+#define DLT_DELU8 8
+#define DLT_ADD16 9
+#define DLT_DEL16 10
+#define DLT_ADDU16 11
+#define DLT_DELU16 12
+#define DLT_SET 13
+#define DLT_R1 14
+#define DLT_R2 15
+
+int _ecore_ipc_log_dom = -1;
+
+EAPI unsigned short
+_ecore_ipc_swap_16(unsigned short v)
+{
+ unsigned char *s, t;
+
+ s = (unsigned char *)(&v);
+ t = s[0]; s[0] = s[1]; s[1] = t;
+ return v;
+}
+
+EAPI unsigned int
+_ecore_ipc_swap_32(unsigned int v)
+{
+ unsigned char *s, t;
+
+ s = (unsigned char *)(&v);
+ t = s[0]; s[0] = s[3]; s[3] = t;
+ t = s[1]; s[1] = s[2]; s[2] = t;
+ return v;
+}
+
+EAPI unsigned long long
+_ecore_ipc_swap_64(unsigned long long v)
+{
+ unsigned char *s, t;
+
+ s = (unsigned char *)(&v);
+ t = s[0]; s[0] = s[7]; s[7] = t;
+ t = s[1]; s[1] = s[6]; s[6] = t;
+ t = s[2]; s[2] = s[5]; s[5] = t;
+ t = s[3]; s[3] = s[4]; s[4] = t;
+ return v;
+}
+
+static int _ecore_ipc_dlt_int(int out, int prev, int *mode);
+static int _ecore_ipc_ddlt_int(int in, int prev, int mode);
+
+static int
+_ecore_ipc_dlt_int(int out, int prev, int *mode)
+{
+ int dlt;
+
+ /* 0 byte */
+ if (out == 0)
+ {
+ *mode = DLT_ZERO;
+ return 0;
+ }
+ if (out == (int)0xffffffff)
+ {
+ *mode = DLT_ONE;
+ return 0;
+ }
+ if (out == prev)
+ {
+ *mode = DLT_SAME;
+ return 0;
+ }
+ if (out == prev << 1)
+ {
+ *mode = DLT_SHL;
+ return 0;
+ }
+ if (out == prev >> 1)
+ {
+ *mode = DLT_SHR;
+ return 0;
+ }
+ /* 1 byte */
+ dlt = out - prev;
+ if (!(dlt & 0xffffff00))
+ {
+ *mode = DLT_ADD8;
+ return dlt & 0xff;
+ }
+ dlt = prev - out;
+ if (!(dlt & 0xffffff00))
+ {
+ *mode = DLT_DEL8;
+ return dlt & 0xff;
+ }
+ dlt = out - prev;
+ if (!(dlt & 0x00ffffff))
+ {
+ *mode = DLT_ADDU8;
+ return (dlt >> 24) & 0xff;
+ }
+ dlt = prev - out;
+ if (!(dlt & 0x00ffffff))
+ {
+ *mode = DLT_DELU8;
+ return (dlt >> 24) & 0xff;
+ }
+ /* 2 byte */
+ dlt = out - prev;
+ if (!(dlt & 0xffff0000))
+ {
+ *mode = DLT_ADD16;
+ return dlt & 0xffff;
+ }
+ dlt = prev - out;
+ if (!(dlt & 0xffff0000))
+ {
+ *mode = DLT_DEL16;
+ return dlt & 0xffff;
+ }
+ dlt = out - prev;
+ if (!(dlt & 0x0000ffff))
+ {
+ *mode = DLT_ADDU16;
+ return (dlt >> 16) & 0xffff;
+ }
+ dlt = prev - out;
+ if (!(dlt & 0x0000ffff))
+ {
+ *mode = DLT_DELU16;
+ return (dlt >> 16) & 0xffff;
+ }
+ /* 4 byte */
+ *mode = DLT_SET;
+ return out;
+}
+
+static int
+_ecore_ipc_ddlt_int(int in, int prev, int mode)
+{
+ switch (mode)
+ {
+ case DLT_ZERO:
+ return 0;
+ break;
+ case DLT_ONE:
+ return 0xffffffff;
+ break;
+ case DLT_SAME:
+ return prev;
+ break;
+ case DLT_SHL:
+ return prev << 1;
+ break;
+ case DLT_SHR:
+ return prev >> 1;
+ break;
+ case DLT_ADD8:
+ return prev + in;
+ break;
+ case DLT_DEL8:
+ return prev - in;
+ break;
+ case DLT_ADDU8:
+ return prev + (in << 24);
+ break;
+ case DLT_DELU8:
+ return prev - (in << 24);
+ break;
+ case DLT_ADD16:
+ return prev + in;
+ break;
+ case DLT_DEL16:
+ return prev - in;
+ break;
+ case DLT_ADDU16:
+ return prev + (in << 16);
+ break;
+ case DLT_DELU16:
+ return prev - (in << 16);
+ break;
+ case DLT_SET:
+ return in;
+ break;
+ case DLT_R1:
+ return 0;
+ break;
+ case DLT_R2:
+ return 0;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Eina_Bool _ecore_ipc_event_client_add(void *data, int ev_type, void *ev);
+static Eina_Bool _ecore_ipc_event_client_del(void *data, int ev_type, void *ev);
+static Eina_Bool _ecore_ipc_event_server_add(void *data, int ev_type, void *ev);
+static Eina_Bool _ecore_ipc_event_server_del(void *data, int ev_type, void *ev);
+static Eina_Bool _ecore_ipc_event_client_data(void *data, int ev_type, void *ev);
+static Eina_Bool _ecore_ipc_event_server_data(void *data, int ev_type, void *ev);
+static void _ecore_ipc_event_client_add_free(void *data, void *ev);
+static void _ecore_ipc_event_client_del_free(void *data, void *ev);
+static void _ecore_ipc_event_client_data_free(void *data, void *ev);
+static void _ecore_ipc_event_server_add_free(void *data, void *ev);
+static void _ecore_ipc_event_server_del_free(void *data, void *ev);
+static void _ecore_ipc_event_server_data_free(void *data, void *ev);
+
+EAPI int ECORE_IPC_EVENT_CLIENT_ADD = 0;
+EAPI int ECORE_IPC_EVENT_CLIENT_DEL = 0;
+EAPI int ECORE_IPC_EVENT_SERVER_ADD = 0;
+EAPI int ECORE_IPC_EVENT_SERVER_DEL = 0;
+EAPI int ECORE_IPC_EVENT_CLIENT_DATA = 0;
+EAPI int ECORE_IPC_EVENT_SERVER_DATA = 0;
+
+static int _ecore_ipc_init_count = 0;
+static Eina_List *servers = NULL;
+static Ecore_Event_Handler *handler[6];
+
+/**
+ * @defgroup Ecore_IPC_Library_Group IPC Library Functions
+ *
+ * Functions that set up and shut down the Ecore IPC Library.
+ */
+
+/**
+ * Initialises the Ecore IPC library.
+ * @return Number of times the library has been initialised without
+ * being shut down.
+ * @ingroup Ecore_IPC_Library_Group
+ */
+EAPI int
+ecore_ipc_init(void)
+{
+ int i = 0;
+
+ if (++_ecore_ipc_init_count != 1)
+ return _ecore_ipc_init_count;
+ _ecore_ipc_log_dom = eina_log_domain_register
+ ("ecore_ipc", ECORE_IPC_DEFAULT_LOG_COLOR);
+ if(_ecore_ipc_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the Ecore IPC module.");
+ return --_ecore_ipc_init_count;
+ }
+ if (!ecore_con_init())
+ return --_ecore_ipc_init_count;
+
+ ECORE_IPC_EVENT_CLIENT_ADD = ecore_event_type_new();
+ ECORE_IPC_EVENT_CLIENT_DEL = ecore_event_type_new();
+ ECORE_IPC_EVENT_SERVER_ADD = ecore_event_type_new();
+ ECORE_IPC_EVENT_SERVER_DEL = ecore_event_type_new();
+ ECORE_IPC_EVENT_CLIENT_DATA = ecore_event_type_new();
+ ECORE_IPC_EVENT_SERVER_DATA = ecore_event_type_new();
+
+ handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD,
+ _ecore_ipc_event_client_add, NULL);
+ handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL,
+ _ecore_ipc_event_client_del, NULL);
+ handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD,
+ _ecore_ipc_event_server_add, NULL);
+ handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL,
+ _ecore_ipc_event_server_del, NULL);
+ handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA,
+ _ecore_ipc_event_client_data, NULL);
+ handler[i] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
+ _ecore_ipc_event_server_data, NULL);
+ return _ecore_ipc_init_count;
+}
+
+/**
+ * Shuts down the Ecore IPC library.
+ * @return Number of times the library has been initialised without being
+ * shut down.
+ * @ingroup Ecore_IPC_Library_Group
+ */
+EAPI int
+ecore_ipc_shutdown(void)
+{
+ int i;
+
+ if (--_ecore_ipc_init_count != 0)
+ return _ecore_ipc_init_count;
+
+ Eina_List *l, *l2;
+ Ecore_Ipc_Server *svr;
+ EINA_LIST_FOREACH_SAFE(servers, l, l2, svr)
+ ecore_ipc_server_del(svr);
+
+ for (i = 0; i < 6; i++)
+ ecore_event_handler_del(handler[i]);
+
+ ecore_con_shutdown();
+ eina_log_domain_unregister(_ecore_ipc_log_dom);
+ _ecore_ipc_log_dom = -1;
+ return _ecore_ipc_init_count;
+}
+
+/**
+ * @defgroup Ecore_IPC_Server_Group IPC Server Functions
+ *
+ * Functions the deal with IPC server objects.
+ */
+
+/**
+ * Creates an IPC server that listens for connections.
+ *
+ * For more details about the @p compl_type, @p name and @p port
+ * parameters, see the @ref ecore_con_server_add documentation.
+ *
+ * @param compl_type The connection type.
+ * @param name Name to associate with the socket used for connection.
+ * @param port Number to identify with socket used for connection.
+ * @param data Data to associate with the IPC server.
+ * @return New IPC server. If there is an error, @c NULL is returned.
+ * @ingroup Ecore_IPC_Server_Group
+ * @todo Need to add protocol type parameter to this function.
+ */
+EAPI Ecore_Ipc_Server *
+ecore_ipc_server_add(Ecore_Ipc_Type compl_type, const char *name, int port, const void *data)
+{
+ Ecore_Ipc_Server *svr;
+ Ecore_Ipc_Type type;
+ Ecore_Con_Type extra = 0;
+
+ if (!name) return NULL;
+
+ svr = calloc(1, sizeof(Ecore_Ipc_Server));
+ if (!svr) return NULL;
+ type = compl_type;
+ type &= ~ECORE_IPC_USE_SSL;
+ if (compl_type & ECORE_IPC_USE_SSL) extra = ECORE_CON_USE_SSL;
+ switch (type)
+ {
+ case ECORE_IPC_LOCAL_USER:
+ svr->server = ecore_con_server_add(ECORE_CON_LOCAL_USER | extra, name, port, svr);
+ break;
+ case ECORE_IPC_LOCAL_SYSTEM:
+ svr->server = ecore_con_server_add(ECORE_CON_LOCAL_SYSTEM | extra, name, port, svr);
+ break;
+ case ECORE_IPC_REMOTE_SYSTEM:
+ svr->server = ecore_con_server_add(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr);
+ break;
+ default:
+ free(svr);
+ return NULL;
+ }
+ if (!svr->server)
+ {
+ free(svr);
+ return NULL;
+ }
+ svr->max_buf_size = 32 * 1024;
+ svr->data = (void *)data;
+ servers = eina_list_append(servers, svr);
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER);
+ return svr;
+}
+
+/**
+ * Creates an IPC server object to represent the IPC server listening
+ * on the given port.
+ *
+ * For more details about the @p compl_type, @p name and @p port
+ * parameters, see the @ref ecore_con_server_connect documentation.
+ *
+ * @param compl_type The IPC connection type.
+ * @param name Name used to determine which socket to use for the
+ * IPC connection.
+ * @param port Number used to identify the socket to use for the
+ * IPC connection.
+ * @param data Data to associate with the server.
+ * @return A new IPC server. @c NULL is returned on error.
+ * @ingroup Ecore_IPC_Server_Group
+ * @todo Need to add protocol type parameter.
+ */
+EAPI Ecore_Ipc_Server *
+ecore_ipc_server_connect(Ecore_Ipc_Type compl_type, char *name, int port, const void *data)
+{
+ Ecore_Ipc_Server *svr;
+ Ecore_Ipc_Type type;
+ Ecore_Con_Type extra = 0;
+ int features;
+
+ svr = calloc(1, sizeof(Ecore_Ipc_Server));
+ if (!svr) return NULL;
+ type = compl_type & ECORE_IPC_TYPE;
+ features = compl_type & ECORE_IPC_SSL;
+ if ((features & ECORE_IPC_USE_SSL) == ECORE_IPC_USE_SSL)
+ extra |= ECORE_CON_USE_SSL;
+ if ((features & ECORE_IPC_NO_PROXY) == ECORE_IPC_NO_PROXY)
+ extra |= ECORE_CON_NO_PROXY;
+ switch (type)
+ {
+ case ECORE_IPC_LOCAL_USER:
+ svr->server = ecore_con_server_connect(ECORE_CON_LOCAL_USER | extra, name, port, svr);
+ break;
+ case ECORE_IPC_LOCAL_SYSTEM:
+ svr->server = ecore_con_server_connect(ECORE_CON_LOCAL_SYSTEM | extra, name, port, svr);
+ break;
+ case ECORE_IPC_REMOTE_SYSTEM:
+ svr->server = ecore_con_server_connect(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr);
+ break;
+ default:
+ free(svr);
+ return NULL;
+ }
+ if (!svr->server)
+ {
+ free(svr);
+ return NULL;
+ }
+ svr->max_buf_size = -1;
+ svr->data = (void *)data;
+ servers = eina_list_append(servers, svr);
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER);
+ return svr;
+}
+
+/**
+ * Closes the connection and frees the given IPC server.
+ * @param svr The given IPC server.
+ * @return The data associated with the server when it was created.
+ * @ingroup Ecore_IPC_Server_Group
+ */
+EAPI void *
+ecore_ipc_server_del(Ecore_Ipc_Server *svr)
+{
+ void *data;
+
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_del");
+ return NULL;
+ }
+ if (svr->delete_me) return NULL;
+
+ data = svr->data;
+ svr->data = NULL;
+ svr->delete_me = 1;
+ if (svr->event_count == 0)
+ {
+ Ecore_Ipc_Client *cl;
+
+ EINA_LIST_FREE(svr->clients, cl)
+ ecore_ipc_client_del(cl);
+ if (svr->server) ecore_con_server_del(svr->server);
+ servers = eina_list_remove(servers, svr);
+
+ if (svr->buf) free(svr->buf);
+ ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE);
+ free(svr);
+ }
+ return data;
+}
+
+/**
+ * Retrieves the data associated with the given IPC server.
+ * @param svr The given IPC server.
+ * @return The associated data.
+ * @ingroup Ecore_IPC_Server_Group
+ */
+EAPI void *
+ecore_ipc_server_data_get(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_data_get");
+ return NULL;
+ }
+ return svr->data;
+}
+
+/**
+ * Retrieves whether the given IPC server is currently connected.
+ * @param svr The given IPC server.
+ * @return @c EINA_TRUE if the server is connected, @c EINA_FALSE otherwise.
+ * @ingroup Ecore_IPC_Server_Group
+ */
+EAPI Eina_Bool
+ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_connected_get");
+ return EINA_FALSE;
+ }
+ return ecore_con_server_connected_get(svr->server);
+}
+
+/**
+ * Retrieves the list of clients for this server.
+ * @param svr The given IPC server.
+ * @return An Eina_List with the clients.
+ * @ingroup Ecore_IPC_Server_Group
+ */
+EAPI Eina_List *
+ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_clients_get");
+ return NULL;
+ }
+ return svr->clients;
+}
+
+#define SVENC(_member) \
+ d = _ecore_ipc_dlt_int(msg._member, svr->prev.o._member, &md); \
+ if (md >= DLT_SET) \
+ { \
+ unsigned int v; \
+ unsigned char *dd; \
+ dd = (unsigned char *)&v; \
+ v = d; \
+ v = htonl(v); \
+ *(dat + s + 0) = dd[0]; \
+ *(dat + s + 1) = dd[1]; \
+ *(dat + s + 2) = dd[2]; \
+ *(dat + s + 3) = dd[3]; \
+ s += 4; \
+ } \
+ else if (md >= DLT_ADD16) \
+ { \
+ unsigned short v; \
+ unsigned char *dd; \
+ dd = (unsigned char *)&v; \
+ v = d; \
+ v = htons(v); \
+ *(dat + s + 0) = dd[0]; \
+ *(dat + s + 1) = dd[1]; \
+ s += 2; \
+ } \
+ else if (md >= DLT_ADD8) \
+ { \
+ *(dat + s + 0) = (unsigned char)d; \
+ s += 1; \
+ }
+
+/**
+ * Sends a message to the given IPC server.
+ *
+ * The content of the parameters, excluding the @p svr paramter, is up to
+ * the client.
+ *
+ * @param svr The given IPC server.
+ * @param major Major opcode of the message.
+ * @param minor Minor opcode of the message.
+ * @param ref Message reference number.
+ * @param ref_to Reference number of the message this message refers to.
+ * @param response Requires response.
+ * @param data The data to send as part of the message.
+ * @param size Length of the data, in bytes, to send.
+ * @return Number of bytes sent. @c 0 is returned if there is an error.
+ * @ingroup Ecore_IPC_Server_Group
+ * @todo This function needs to become an IPC message.
+ * @todo Fix up the documentation: Make sure what ref_to and response are.
+ */
+EAPI int
+ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int ref_to, int response, const void *data, int size)
+{
+ Ecore_Ipc_Msg_Head msg;
+ int ret;
+ int *head, md = 0, d, s;
+ unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)];
+
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_send");
+ return 0;
+ }
+ if (size < 0) size = 0;
+ msg.major = major;
+ msg.minor = minor;
+ msg.ref = ref;
+ msg.ref_to = ref_to;
+ msg.response = response;
+ msg.size = size;
+ head = (int *)dat;
+ s = 4;
+ SVENC(major);
+ *head = md;
+ SVENC(minor);
+ *head |= md << (4 * 1);
+ SVENC(ref);
+ *head |= md << (4 * 2);
+ SVENC(ref_to);
+ *head |= md << (4 * 3);
+ SVENC(response);
+ *head |= md << (4 * 4);
+ SVENC(size);
+ *head |= md << (4 * 5);
+ *head = htonl(*head);
+ svr->prev.o = msg;
+ ret = ecore_con_server_send(svr->server, dat, s);
+ if (size > 0) ret += ecore_con_server_send(svr->server, data, size);
+ return ret;
+}
+
+/**
+ * Sets a limit on the number of clients that can be handled concurrently
+ * by the given server, and a policy on what to do if excess clients try to
+ * connect.
+ * Beware that if you set this once ecore is already running, you may
+ * already have pending CLIENT_ADD events in your event queue. Those
+ * clients have already connected and will not be affected by this call.
+ * Only clients subsequently trying to connect will be affected.
+ * @param svr The given server.
+ * @param client_limit The maximum number of clients to handle
+ * concurrently. -1 means unlimited (default). 0
+ * effectively disables the server.
+ * @param reject_excess_clients Set to 1 to automatically disconnect
+ * excess clients as soon as they connect if you are
+ * already handling client_limit clients. Set to 0
+ * (default) to just hold off on the "accept()"
+ * system call until the number of active clients
+ * drops. This causes the kernel to queue up to 4096
+ * connections (or your kernel's limit, whichever is
+ * lower).
+ * @ingroup Ecore_Ipc_Server_Group
+ */
+EAPI void
+ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char reject_excess_clients)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_client_limit_set");
+ return;
+ }
+ ecore_con_server_client_limit_set(svr->server, client_limit, reject_excess_clients);
+}
+
+/**
+ * Sets the max data payload size for an Ipc message in bytes
+ *
+ * @param svr The given server.
+ * @param size The maximum data payload size in bytes.
+ * @ingroup Ecore_Ipc_Server_Group
+ */
+EAPI void
+ecore_ipc_server_data_size_max_set(Ecore_Ipc_Server *svr, int size)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_data_size_max_set");
+ return;
+ }
+ svr->max_buf_size = size;
+}
+
+/**
+ * Gets the max data payload size for an Ipc message in bytes
+ *
+ * @param svr The given server.
+ * @return The maximum data payload in bytes.
+ * @ingroup Ecore_Ipc_Server_Group
+ */
+EAPI int
+ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_data_size_max_get");
+ return -1;
+ }
+ return svr->max_buf_size;
+}
+
+/**
+ * Gets the IP address of a server that has been connected to.
+ *
+ * @param svr The given server.
+ * @return A pointer to an internal string that contains the IP address of
+ * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation.
+ * This string should not be modified or trusted to stay valid after
+ * deletion for the @p svr object. If no IP is known NULL is returned.
+ * @ingroup Ecore_Ipc_Server_Group
+ */
+EAPI const char *
+ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_ip_get");
+ return NULL;
+ }
+ return ecore_con_server_ip_get(svr->server);
+}
+
+/**
+ * Flushes all pending data to the given server. Will return when done.
+ *
+ * @param svr The given server.
+ * @ingroup Ecore_Ipc_Server_Group
+ */
+EAPI void
+ecore_ipc_server_flush(Ecore_Ipc_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER,
+ "ecore_ipc_server_server_flush");
+ return;
+ }
+ ecore_con_server_flush(svr->server);
+}
+
+#define CLENC(_member) \
+ d = _ecore_ipc_dlt_int(msg._member, cl->prev.o._member, &md); \
+ if (md >= DLT_SET) \
+ { \
+ unsigned int v; \
+ unsigned char *dd; \
+ dd = (unsigned char *)&v; \
+ v = d; \
+ v = htonl(v); \
+ *(dat + s + 0) = dd[0]; \
+ *(dat + s + 1) = dd[1]; \
+ *(dat + s + 2) = dd[2]; \
+ *(dat + s + 3) = dd[3]; \
+ s += 4; \
+ } \
+ else if (md >= DLT_ADD16) \
+ { \
+ unsigned short v; \
+ unsigned char *dd; \
+ dd = (unsigned char *)&v; \
+ v = d; \
+ v = htons(v); \
+ *(dat + s + 0) = dd[0]; \
+ *(dat + s + 1) = dd[1]; \
+ s += 2; \
+ } \
+ else if (md >= DLT_ADD8) \
+ { \
+ *(dat + s) = (unsigned char)d; \
+ s += 1; \
+ }
+
+/**
+ * @defgroup Ecore_IPC_Client_Group IPC Client Functions
+ *
+ * Functions that deal with IPC client objects.
+ */
+
+/**
+ * Sends a message to the given IPC client.
+ * @param cl The given IPC client.
+ * @param major Major opcode of the message.
+ * @param minor Minor opcode of the message.
+ * @param ref Reference number of the message.
+ * @param ref_to Reference number of the message this message refers to.
+ * @param response Requires response.
+ * @param data The data to send as part of the message.
+ * @param size Length of the data, in bytes, to send.
+ * @return The number of bytes sent. @c 0 will be returned if there is
+ * an error.
+ * @ingroup Ecore_IPC_Client_Group
+ * @todo This function needs to become an IPC message.
+ * @todo Make sure ref_to and response parameters are described correctly.
+ */
+EAPI int
+ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int ref_to, int response, const void *data, int size)
+{
+ Ecore_Ipc_Msg_Head msg;
+ int ret;
+ int *head, md = 0, d, s;
+ unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)];
+
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_send");
+ return 0;
+ }
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!cl->client, 0);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_connected_get(cl->client), 0);
+ if (size < 0) size = 0;
+ msg.major = major;
+ msg.minor = minor;
+ msg.ref = ref;
+ msg.ref_to = ref_to;
+ msg.response = response;
+ msg.size = size;
+ head = (int *)dat;
+ s = 4;
+ CLENC(major);
+ *head = md;
+ CLENC(minor);
+ *head |= md << (4 * 1);
+ CLENC(ref);
+ *head |= md << (4 * 2);
+ CLENC(ref_to);
+ *head |= md << (4 * 3);
+ CLENC(response);
+ *head |= md << (4 * 4);
+ CLENC(size);
+ *head |= md << (4 * 5);
+ *head = htonl(*head);
+ cl->prev.o = msg;
+ ret = ecore_con_client_send(cl->client, dat, s);
+ if (size > 0) ret += ecore_con_client_send(cl->client, data, size);
+ return ret;
+}
+
+/**
+ * Retrieves the IPC server that the given IPC client is connected to.
+ * @param cl The given IPC client.
+ * @return The IPC server the IPC client is connected to.
+ * @ingroup Ecore_IPC_Client_Group
+ */
+EAPI Ecore_Ipc_Server *
+ecore_ipc_client_server_get(Ecore_Ipc_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_server_get");
+ return NULL;
+ }
+ return cl->svr;
+}
+
+/**
+ * Closes the connection and frees memory allocated to the given IPC
+ * client.
+ * @param cl The given client.
+ * @return Data associated with the client.
+ * @ingroup Ecore_IPC_Client_Group
+ */
+EAPI void *
+ecore_ipc_client_del(Ecore_Ipc_Client *cl)
+{
+ void *data;
+ Ecore_Ipc_Server *svr;
+
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_del");
+ return NULL;
+ }
+ data = cl->data;
+ cl->data = NULL;
+ cl->delete_me = 1;
+ if (cl->event_count == 0)
+ {
+ svr = cl->svr;
+ if (cl->client) ecore_con_client_del(cl->client);
+ svr->clients = eina_list_remove(svr->clients, cl);
+ if (cl->buf) free(cl->buf);
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE);
+ free(cl);
+ }
+ return data;
+}
+
+/**
+ * Sets the IPC data associated with the given IPC client to @p data.
+ * @param cl The given IPC client.
+ * @param data The data to associate with the IPC client.
+ * @ingroup Ecore_IPC_Client_Group
+ */
+EAPI void
+ecore_ipc_client_data_set(Ecore_Ipc_Client *cl, const void *data)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_data_set");
+ return;
+ }
+ cl->data = (void *)data;
+}
+
+/**
+ * Retrieves the data that has been associated with the given IPC client.
+ * @param cl The given client.
+ * @return The data associated with the IPC client.
+ * @ingroup Ecore_IPC_Client_Group
+ */
+EAPI void *
+ecore_ipc_client_data_get(Ecore_Ipc_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_data_get");
+ return NULL;
+ }
+ return cl->data;
+}
+
+/**
+ * Sets the max data payload size for an Ipc message in bytes
+ *
+ * @param cl The given client.
+ * @param size The maximum data payload size in bytes.
+ * @ingroup Ecore_Ipc_Client_Group
+ */
+EAPI void
+ecore_ipc_client_data_size_max_set(Ecore_Ipc_Client *cl, int size)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_data_size_max_set");
+ return;
+ }
+ cl->max_buf_size = size;
+}
+
+/**
+ * Gets the max data payload size for an Ipc message in bytes
+ *
+ * @param cl The given client.
+ * @return The maximum data payload size in bytes on success, @c -1 on failure.
+ * @ingroup Ecore_Ipc_Client_Group
+ */
+EAPI int
+ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_data_size_max_get");
+ return -1;
+ }
+ return cl->max_buf_size;
+}
+
+/**
+ * Gets the IP address of a client that has been connected to.
+ *
+ * @param cl The given client.
+ * @return A pointer to an internal string that contains the IP address of
+ * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation.
+ * This string should not be modified or trusted to stay valid after
+ * deletion for the @p cl object. If no IP is known @c NULL is
+ * returned.
+ * @ingroup Ecore_Ipc_Client_Group
+ */
+EAPI const char *
+ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_ip_get");
+ return NULL;
+ }
+ return ecore_con_client_ip_get(cl->client);
+}
+
+/**
+ * Flushes all pending data to the given client. Will return when done.
+ *
+ * @param cl The given client.
+ * @ingroup Ecore_Ipc_Client_Group
+ */
+EAPI void
+ecore_ipc_client_flush(Ecore_Ipc_Client *cl)
+{
+ if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT))
+ {
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT,
+ "ecore_ipc_client_flush");
+ return;
+ }
+ ecore_con_client_flush(cl->client);
+}
+
+/**
+ * Returns if SSL support is available
+ * @return 1 if SSL is available, 0 if it is not.
+ * @ingroup Ecore_Con_Client_Group
+ */
+EAPI int
+ecore_ipc_ssl_available_get(void)
+{
+ return ecore_con_ssl_available_get();
+}
+
+
+static Eina_Bool
+_ecore_ipc_event_client_add(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Client_Add *e;
+ Ecore_Ipc_Server *svr;
+
+ e = ev;
+ svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client));
+ if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Client *cl;
+
+ cl = calloc(1, sizeof(Ecore_Ipc_Client));
+ if (!cl) return ECORE_CALLBACK_CANCEL;
+ cl->svr = svr;
+ ECORE_MAGIC_SET(cl, ECORE_MAGIC_IPC_CLIENT);
+ cl->client = e->client;
+ cl->max_buf_size = 32 * 1024;
+ ecore_con_client_data_set(cl->client, (void *)cl);
+ svr->clients = eina_list_append(svr->clients, cl);
+ if (!cl->delete_me)
+ {
+ Ecore_Ipc_Event_Client_Add *e2;
+
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Add));
+ if (e2)
+ {
+ cl->event_count++;
+ e2->client = cl;
+ ecore_event_add(ECORE_IPC_EVENT_CLIENT_ADD, e2,
+ _ecore_ipc_event_client_add_free, NULL);
+ }
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_ipc_event_client_del(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Client_Del *e;
+ Ecore_Ipc_Server *svr;
+
+ e = ev;
+ if (!e->client) return ECORE_CALLBACK_RENEW;
+ svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client));
+ if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Client *cl;
+
+ cl = ecore_con_client_data_get(e->client);
+ cl->client = NULL;
+ {
+ Ecore_Ipc_Event_Client_Del *e2;
+
+ if (!cl->delete_me)
+ {
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Del));
+ if (e2)
+ {
+ cl->event_count++;
+ e2->client = cl;
+ ecore_event_add(ECORE_IPC_EVENT_CLIENT_DEL, e2,
+ _ecore_ipc_event_client_del_free, NULL);
+ }
+ }
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_ipc_event_server_add(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Server_Add *e;
+
+ e = ev;
+ if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Server *svr;
+
+ svr = ecore_con_server_data_get(e->server);
+ if (!svr->delete_me)
+ {
+ Ecore_Ipc_Event_Server_Add *e2;
+
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Add));
+ if (e2)
+ {
+ svr->event_count++;
+ e2->server = svr;
+ ecore_event_add(ECORE_IPC_EVENT_SERVER_ADD, e2,
+ _ecore_ipc_event_server_add_free, NULL);
+ }
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_ipc_event_server_del(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Server_Del *e;
+
+ e = ev;
+ if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Server *svr;
+
+ svr = ecore_con_server_data_get(e->server);
+ svr->server = NULL;
+ if (!svr->delete_me)
+ {
+ Ecore_Ipc_Event_Server_Del *e2;
+
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Del));
+ if (e2)
+ {
+ svr->event_count++;
+ e2->server = svr;
+ ecore_event_add(ECORE_IPC_EVENT_SERVER_DEL, e2,
+ _ecore_ipc_event_server_del_free, NULL);
+ }
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+#define CLSZ(_n) \
+ md = ((head >> (4 * _n)) & 0xf); \
+ if (md >= DLT_SET) s += 4; \
+ else if (md >= DLT_ADD16) s += 2; \
+ else if (md >= DLT_ADD8) s += 1;
+
+#define CLDEC(_n, _member) \
+ md = ((head >> (4 * _n)) & 0xf); \
+ if (md >= DLT_SET) \
+ { \
+ unsigned int v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(cl->buf + offset + s + 0); \
+ dv[1] = *(cl->buf + offset + s + 1); \
+ dv[2] = *(cl->buf + offset + s + 2); \
+ dv[3] = *(cl->buf + offset + s + 3); \
+ d = (int)ntohl(v); \
+ s += 4; \
+ } \
+ else if (md >= DLT_ADD16) \
+ { \
+ unsigned short v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(cl->buf + offset + s + 0); \
+ dv[1] = *(cl->buf + offset + s + 1); \
+ d = (int)ntohs(v); \
+ s += 2; \
+ } \
+ else if (md >= DLT_ADD8) \
+ { \
+ unsigned char v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(cl->buf + offset + s + 0); \
+ d = (int)v; \
+ s += 1; \
+ } \
+ msg._member = _ecore_ipc_ddlt_int(d, cl->prev.i._member, md);
+
+static Eina_Bool
+_ecore_ipc_event_client_data(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Client_Data *e;
+ Ecore_Ipc_Server *svr;
+
+ e = ev;
+ svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client));
+ if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Client *cl;
+ Ecore_Ipc_Msg_Head msg;
+ int offset = 0;
+ unsigned char *buf;
+
+ cl = ecore_con_client_data_get(e->client);
+
+ if (!cl->buf)
+ {
+ cl->buf_size = e->size;
+ cl->buf = e->data;
+ e->data = NULL; /* take it out of the old event */
+ }
+ else
+ {
+ buf = realloc(cl->buf, cl->buf_size + e->size);
+ if (!buf)
+ {
+ free(cl->buf);
+ cl->buf = 0;
+ cl->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ cl->buf = buf;
+ memcpy(cl->buf + cl->buf_size, e->data, e->size);
+ cl->buf_size += e->size;
+ }
+ /* examine header */
+ redo:
+ if ((cl->buf_size - offset) >= (int)sizeof(int))
+ {
+ int s, md, d = 0, head;
+ unsigned char *dd;
+
+ dd = (unsigned char *)&head;
+ dd[0] = *(cl->buf + offset + 0);
+ dd[1] = *(cl->buf + offset + 1);
+ dd[2] = *(cl->buf + offset + 2);
+ dd[3] = *(cl->buf + offset + 3);
+ head = ntohl(head);
+ dd = (unsigned char *)&d;
+ s = 4;
+ CLSZ(0);
+ CLSZ(1);
+ CLSZ(2);
+ CLSZ(3);
+ CLSZ(4);
+ CLSZ(5);
+ if ((cl->buf_size - offset) < s)
+ {
+ if (offset > 0) goto scroll;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ s = 4;
+ CLDEC(0, major);
+ CLDEC(1, minor);
+ CLDEC(2, ref);
+ CLDEC(3, ref_to);
+ CLDEC(4, response);
+ CLDEC(5, size);
+ if (msg.size < 0) msg.size = 0;
+ /* there is enough data in the buffer for a full message */
+ if ((cl->buf_size - offset) >= (s + msg.size))
+ {
+ Ecore_Ipc_Event_Client_Data *e2;
+ int max, max2;
+
+ buf = NULL;
+ max = svr->max_buf_size;
+ max2 = cl->max_buf_size;
+ if ((max >= 0) && (max2 >= 0))
+ {
+ if (max2 < max) max = max2;
+ }
+ else
+ {
+ if (max < 0) max = max2;
+ }
+ if ((max < 0) || (msg.size <= max))
+ {
+ if (msg.size > 0)
+ {
+ buf = malloc(msg.size);
+ if (!buf) return ECORE_CALLBACK_CANCEL;
+ memcpy(buf, cl->buf + offset + s, msg.size);
+ }
+ if (!cl->delete_me)
+ {
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Data));
+ if (e2)
+ {
+ cl->event_count++;
+ e2->client = cl;
+ e2->major = msg.major;
+ e2->minor = msg.minor;
+ e2->ref = msg.ref;
+ e2->ref_to = msg.ref_to;
+ e2->response = msg.response;
+ e2->size = msg.size;
+ e2->data = buf;
+ ecore_event_add(ECORE_IPC_EVENT_CLIENT_DATA, e2,
+ _ecore_ipc_event_client_data_free,
+ NULL);
+ }
+ }
+ }
+ cl->prev.i = msg;
+ offset += (s + msg.size);
+ if (cl->buf_size == offset)
+ {
+ free(cl->buf);
+ cl->buf = NULL;
+ cl->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ goto redo;
+ }
+ else goto scroll;
+ }
+ else
+ {
+ scroll:
+ buf = malloc(cl->buf_size - offset);
+ if (!buf)
+ {
+ free(cl->buf);
+ cl->buf = NULL;
+ cl->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ memcpy(buf, cl->buf + offset, cl->buf_size - offset);
+ free(cl->buf);
+ cl->buf = buf;
+ cl->buf_size -= offset;
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+#define SVSZ(_n) \
+ md = ((head >> (4 * _n)) & 0xf); \
+ if (md >= DLT_SET) s += 4; \
+ else if (md >= DLT_ADD16) s += 2; \
+ else if (md >= DLT_ADD8) s += 1;
+
+#define SVDEC(_n, _member) \
+ md = ((head >> (4 * _n)) & 0xf); \
+ if (md >= DLT_SET) \
+ { \
+ unsigned int v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(svr->buf + offset + s + 0); \
+ dv[1] = *(svr->buf + offset + s + 1); \
+ dv[2] = *(svr->buf + offset + s + 2); \
+ dv[3] = *(svr->buf + offset + s + 3); \
+ d = (int)ntohl(v); \
+ s += 4; \
+ } \
+ else if (md >= DLT_ADD16) \
+ { \
+ unsigned short v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(svr->buf + offset + s + 0); \
+ dv[1] = *(svr->buf + offset + s + 1); \
+ d = (int)ntohs(v); \
+ s += 2; \
+ } \
+ else if (md >= DLT_ADD8) \
+ { \
+ unsigned char v; \
+ unsigned char *dv; \
+ dv = (unsigned char *)&v; \
+ dv[0] = *(svr->buf + offset + s + 0); \
+ d = (int)v; \
+ s += 1; \
+ } \
+ msg._member = _ecore_ipc_ddlt_int(d, svr->prev.i._member, md);
+
+static Eina_Bool
+_ecore_ipc_event_server_data(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev)
+{
+ Ecore_Con_Event_Server_Data *e;
+
+ e = ev;
+ if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW;
+ /* handling code here */
+ {
+ Ecore_Ipc_Server *svr;
+ Ecore_Ipc_Msg_Head msg;
+ int offset = 0;
+ unsigned char *buf;
+
+ svr = ecore_con_server_data_get(e->server);
+
+ if (!svr->buf)
+ {
+ svr->buf_size = e->size;
+ svr->buf = e->data;
+ e->data = NULL; /* take it out of the old event */
+ }
+ else
+ {
+ buf = realloc(svr->buf, svr->buf_size + e->size);
+ if (!buf)
+ {
+ free(svr->buf);
+ svr->buf = 0;
+ svr->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ svr->buf = buf;
+ memcpy(svr->buf + svr->buf_size, e->data, e->size);
+ svr->buf_size += e->size;
+ }
+ /* examine header */
+ redo:
+ if ((svr->buf_size - offset) >= (int)sizeof(int))
+ {
+ int s, md, d = 0, head;
+ unsigned char *dd;
+
+ dd = (unsigned char *)&head;
+ dd[0] = *(svr->buf + offset + 0);
+ dd[1] = *(svr->buf + offset + 1);
+ dd[2] = *(svr->buf + offset + 2);
+ dd[3] = *(svr->buf + offset + 3);
+ head = ntohl(head);
+ dd = (unsigned char *)&d;
+ s = 4;
+ SVSZ(0);
+ SVSZ(1);
+ SVSZ(2);
+ SVSZ(3);
+ SVSZ(4);
+ SVSZ(5);
+ if ((svr->buf_size - offset) < s)
+ {
+ if (offset > 0) goto scroll;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ s = 4;
+ SVDEC(0, major);
+ SVDEC(1, minor);
+ SVDEC(2, ref);
+ SVDEC(3, ref_to);
+ SVDEC(4, response);
+ SVDEC(5, size);
+ if (msg.size < 0) msg.size = 0;
+ /* there is enough data in the buffer for a full message */
+ if ((svr->buf_size - offset) >= (s + msg.size))
+ {
+ Ecore_Ipc_Event_Server_Data *e2;
+ int max;
+
+ buf = NULL;
+ max = svr->max_buf_size;
+ if ((max < 0) || (msg.size <= max))
+ {
+ if (msg.size > 0)
+ {
+ buf = malloc(msg.size);
+ if (!buf) return ECORE_CALLBACK_CANCEL;
+ memcpy(buf, svr->buf + offset + s, msg.size);
+ }
+ if (!svr->delete_me)
+ {
+ e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Data));
+ if (e2)
+ {
+ svr->event_count++;
+ e2->server = svr;
+ e2->major = msg.major;
+ e2->minor = msg.minor;
+ e2->ref = msg.ref;
+ e2->ref_to = msg.ref_to;
+ e2->response = msg.response;
+ e2->size = msg.size;
+ e2->data = buf;
+ ecore_event_add(ECORE_IPC_EVENT_SERVER_DATA, e2,
+ _ecore_ipc_event_server_data_free,
+ NULL);
+ }
+ }
+ }
+ svr->prev.i = msg;
+ offset += (s + msg.size);
+ if (svr->buf_size == offset)
+ {
+ free(svr->buf);
+ svr->buf = NULL;
+ svr->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ goto redo;
+ }
+ else goto scroll;
+ }
+ else
+ {
+ scroll:
+ buf = malloc(svr->buf_size - offset);
+ if (!buf)
+ {
+ free(svr->buf);
+ svr->buf = NULL;
+ svr->buf_size = 0;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ memcpy(buf, svr->buf + offset, svr->buf_size - offset);
+ free(svr->buf);
+ svr->buf = buf;
+ svr->buf_size -= offset;
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_ipc_event_client_add_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Client_Add *e;
+
+ e = ev;
+ e->client->event_count--;
+ if ((e->client->event_count == 0) && (e->client->delete_me))
+ ecore_ipc_client_del(e->client);
+ free(e);
+}
+
+static void
+_ecore_ipc_event_client_del_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Client_Del *e;
+
+ e = ev;
+ e->client->event_count--;
+ if ((e->client->event_count == 0) && (e->client->delete_me))
+ ecore_ipc_client_del(e->client);
+ free(e);
+}
+
+static void
+_ecore_ipc_event_client_data_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Client_Data *e;
+
+ e = ev;
+ e->client->event_count--;
+ if (e->data) free(e->data);
+ if ((e->client->event_count == 0) && (e->client->delete_me))
+ ecore_ipc_client_del(e->client);
+ free(e);
+}
+
+static void
+_ecore_ipc_event_server_add_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Server_Add *e;
+
+ e = ev;
+ e->server->event_count--;
+ if ((e->server->event_count == 0) && (e->server->delete_me))
+ ecore_ipc_server_del(e->server);
+ free(e);
+}
+
+static void
+_ecore_ipc_event_server_del_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Server_Add *e;
+
+ e = ev;
+ e->server->event_count--;
+ if ((e->server->event_count == 0) && (e->server->delete_me))
+ ecore_ipc_server_del(e->server);
+ free(e);
+}
+
+static void
+_ecore_ipc_event_server_data_free(void *data EINA_UNUSED, void *ev)
+{
+ Ecore_Ipc_Event_Server_Data *e;
+
+ e = ev;
+ if (e->data) free(e->data);
+ e->server->event_count--;
+ if ((e->server->event_count == 0) && (e->server->delete_me))
+ ecore_ipc_server_del(e->server);
+ free(e);
+}
diff --git a/src/lib/ecore_ipc/ecore_ipc_private.h b/src/lib/ecore_ipc/ecore_ipc_private.h
new file mode 100644
index 0000000000..bedaab167c
--- /dev/null
+++ b/src/lib/ecore_ipc/ecore_ipc_private.h
@@ -0,0 +1,105 @@
+#ifndef _ECORE_IPC_PRIVATE_H
+#define _ECORE_IPC_PRIVATE_H
+
+
+extern int _ecore_ipc_log_dom;
+
+#ifdef ECORE_IPC_DEFAULT_LOG_COLOR
+# undef ECORE_IPC_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_IPC_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_ipc_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_ipc_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_ipc_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_ipc_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_ipc_log_dom, __VA_ARGS__)
+
+#define ECORE_MAGIC_IPC_SERVER 0x87786556
+#define ECORE_MAGIC_IPC_CLIENT 0x78875665
+
+typedef struct _Ecore_Ipc_Msg_Head Ecore_Ipc_Msg_Head;
+#define ECORE_IPC_TYPE 0x0f
+#define ECORE_IPC_SSL 0xf0
+
+#if defined (_MSC_VER) || (defined (__SUNPRO_C) && __SUNPRO_C < 0x5100)
+# pragma pack(1)
+# define ECORE_IPC_STRUCT_PACKED
+#elif defined (__GNUC__) || (defined (__SUNPRO_C) && __SUNPRO_C >= 0x5100)
+# define ECORE_IPC_STRUCT_PACKED __attribute__((packed))
+#else
+# define ECORE_IPC_STRUCT_PACKED
+#endif
+
+#ifdef __sgi
+#pragma pack 4
+#endif
+struct _Ecore_Ipc_Msg_Head
+{
+ int major;
+ int minor;
+ int ref;
+ int ref_to;
+ int response;
+ int size;
+} ECORE_IPC_STRUCT_PACKED;
+#ifdef __sgi
+#pragma pack 0
+#endif
+
+struct _Ecore_Ipc_Client
+{
+ ECORE_MAGIC;
+ Ecore_Con_Client *client;
+ Ecore_Ipc_Server *svr;
+ void *data;
+ unsigned char *buf;
+ int buf_size;
+ int max_buf_size;
+
+ struct {
+ Ecore_Ipc_Msg_Head i, o;
+ } prev;
+
+ int event_count;
+ char delete_me : 1;
+};
+
+struct _Ecore_Ipc_Server
+{
+ ECORE_MAGIC;
+ Ecore_Con_Server *server;
+ Eina_List *clients;
+ void *data;
+ unsigned char *buf;
+ int buf_size;
+ int max_buf_size;
+
+ struct {
+ Ecore_Ipc_Msg_Head i, o;
+ } prev;
+
+ int event_count;
+ char delete_me : 1;
+};
+
+#endif
diff --git a/src/lib/ecore_sdl/Ecore_Sdl.h b/src/lib/ecore_sdl/Ecore_Sdl.h
new file mode 100644
index 0000000000..359e974718
--- /dev/null
+++ b/src/lib/ecore_sdl/Ecore_Sdl.h
@@ -0,0 +1,114 @@
+#ifndef _ECORE_SDL_H
+#define _ECORE_SDL_H
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_SDL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_SDL_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file
+ * @brief Ecore SDL system functions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EAPI extern int ECORE_SDL_EVENT_GOT_FOCUS;
+EAPI extern int ECORE_SDL_EVENT_LOST_FOCUS;
+EAPI extern int ECORE_SDL_EVENT_RESIZE;
+EAPI extern int ECORE_SDL_EVENT_EXPOSE;
+
+typedef struct _Ecore_Sdl_Event_Key_Down Ecore_Sdl_Event_Key_Down;
+struct _Ecore_Sdl_Event_Key_Down /** SDL Key Down event */
+{
+ const char *keyname; /**< The name of the key that was pressed */
+ const char *keycompose; /**< The UTF-8 string conversion if any */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Key_Up Ecore_Sdl_Event_Key_Up;
+struct _Ecore_Sdl_Event_Key_Up /** SDL Key Up event */
+{
+ const char *keyname; /**< The name of the key that was released */
+ const char *keycompose; /**< The UTF-8 string conversion if any */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Mouse_Button_Down Ecore_Sdl_Event_Mouse_Button_Down;
+struct _Ecore_Sdl_Event_Mouse_Button_Down /** SDL Mouse Down event */
+{
+ int button; /**< Mouse button that was pressed (1 - 32) */
+ int x; /**< Mouse co-ordinates when mouse button was pressed */
+ int y; /**< Mouse co-ordinates when mouse button was pressed */
+ int double_click : 1; /**< Set if click was a double click */
+ int triple_click : 1; /**< Set if click was a triple click */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Mouse_Button_Up Ecore_Sdl_Event_Mouse_Button_Up;
+struct _Ecore_Sdl_Event_Mouse_Button_Up /** SDL Mouse Up event */
+{
+ int button; /**< Mouse button that was released (1 - 32) */
+ int x; /**< Mouse co-ordinates when mouse button was raised */
+ int y; /**< Mouse co-ordinates when mouse button was raised */
+ int double_click : 1; /**< Set if click was a double click */
+ int triple_click : 1; /**< Set if click was a triple click */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Mouse_Move Ecore_Sdl_Event_Mouse_Move;
+struct _Ecore_Sdl_Event_Mouse_Move /** SDL Mouse Move event */
+{
+ int x; /**< Mouse co-ordinates where the mouse cursor moved to */
+ int y; /**< Mouse co-ordinates where the mouse cursor moved to */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Mouse_Wheel Ecore_Sdl_Event_Mouse_Wheel;
+struct _Ecore_Sdl_Event_Mouse_Wheel /** SDL Mouse Wheel event */
+{
+ int x,y;
+ int direction; /* 0 = vertical, 1 = horizontal */
+ int wheel; /* value 1 (left/up), -1 (right/down) */
+ unsigned int time;
+};
+
+typedef struct _Ecore_Sdl_Event_Video_Resize Ecore_Sdl_Event_Video_Resize;
+struct _Ecore_Sdl_Event_Video_Resize
+{
+ int w;
+ int h;
+};
+
+EAPI int ecore_sdl_init(const char *name);
+EAPI int ecore_sdl_shutdown(void);
+EAPI void ecore_sdl_feed_events(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_sdl/Ecore_Sdl_Keys.h b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h
new file mode 100644
index 0000000000..4d0b60b854
--- /dev/null
+++ b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h
@@ -0,0 +1,266 @@
+#ifndef ECORE_SDL_KEYS_H__
+# define ECORE_SDL_KEYS_H__
+
+struct _ecore_sdl_keys_s
+{
+ int code;
+ const char* name;
+ const char* compose;
+};
+
+static const struct _ecore_sdl_keys_s keystable[] =
+{
+ { SDLK_UNKNOWN, "0x00", "" },
+#ifndef BUILD_ECORE_EVAS_SDL_130
+ { SDLK_FIRST, "First", "First" },
+#endif
+ { SDLK_BACKSPACE, "BackSpace", "\010" },
+ { SDLK_TAB, "Tab", "\011" },
+ { SDLK_CLEAR, "Clear", "Clear" },
+ { SDLK_RETURN, "Return", "\015" },
+ { SDLK_PAUSE, "Pause", "Pause" },
+ { SDLK_ESCAPE, "Escape", "\033" },
+ { SDLK_SPACE, "space", " " },
+ { SDLK_EXCLAIM, "exclam", "!" },
+ { SDLK_QUOTEDBL, "quotedbl", "\"" },
+ { SDLK_HASH, "numbersign", "#" },
+ { SDLK_DOLLAR, "dollar", "$" },
+ { SDLK_AMPERSAND, "ampersand", "&" },
+ { SDLK_QUOTE, "apostrophe", "'" },
+ { SDLK_LEFTPAREN, "parenleft", "(" },
+ { SDLK_RIGHTPAREN, "parenright", ")" },
+ { SDLK_ASTERISK, "asterisk", "*" },
+ { SDLK_PLUS, "plus", "+" },
+ { SDLK_COMMA, "comma", "," },
+ { SDLK_MINUS, "minus", "-" },
+ { SDLK_PERIOD, "period", "." },
+ { SDLK_SLASH, "slash", "/" },
+ { SDLK_0, "0", "0" },
+ { SDLK_1, "1", "1" },
+ { SDLK_2, "2", "2" },
+ { SDLK_3, "3", "3" },
+ { SDLK_4, "4", "4" },
+ { SDLK_5, "5", "5" },
+ { SDLK_6, "6", "6" },
+ { SDLK_7, "7", "7" },
+ { SDLK_8, "8", "8" },
+ { SDLK_9, "9", "9" },
+ { SDLK_COLON, "colon", ":" },
+ { SDLK_SEMICOLON, "semicolon", ";" },
+ { SDLK_LESS, "less", "<" },
+ { SDLK_EQUALS, "equal", "=" },
+ { SDLK_GREATER, "greater", ">" },
+ { SDLK_QUESTION, "question", "?" },
+ { SDLK_AT, "at", "@" },
+
+ /* Skip uppercase letters */
+ { SDLK_LEFTBRACKET, "bracketleft", "[" },
+ { SDLK_BACKSLASH, "backslash", "\\" },
+ { SDLK_RIGHTBRACKET, "bracketright", "]" },
+ { SDLK_CARET, "asciicircumm", "^" },
+ { SDLK_UNDERSCORE, "underscore", "_" },
+ { SDLK_BACKQUOTE, "asciitilde", "`" },
+ { SDLK_a, "a", "a" },
+ { SDLK_b, "b", "b" },
+ { SDLK_c, "c", "c" },
+ { SDLK_d, "d", "d" },
+ { SDLK_e, "e", "e" },
+ { SDLK_f, "f", "f" },
+ { SDLK_g, "g", "g" },
+ { SDLK_h, "h", "h" },
+ { SDLK_i, "i", "i" },
+ { SDLK_j, "j", "j" },
+ { SDLK_k, "k", "k" },
+ { SDLK_l, "l", "l" },
+ { SDLK_m, "m", "m" },
+ { SDLK_n, "n", "n" },
+ { SDLK_o, "o", "o" },
+ { SDLK_p, "p", "p" },
+ { SDLK_q, "q", "q" },
+ { SDLK_r, "r", "r" },
+ { SDLK_s, "s", "s" },
+ { SDLK_t, "t", "t" },
+ { SDLK_u, "u", "u" },
+ { SDLK_v, "v", "v" },
+ { SDLK_w, "w", "w" },
+ { SDLK_x, "x", "x" },
+ { SDLK_y, "y", "y" },
+ { SDLK_z, "z", "z" },
+ { SDLK_DELETE, "Delete", "\177" },
+ /* End of ASCII mapped keysyms */
+
+#ifndef BUILD_ECORE_EVAS_SDL_130
+ /* International keyboard syms */
+ { SDLK_WORLD_0, "w0", "" }, /* 0xA0 */
+ { SDLK_WORLD_1, "w1", "" },
+ { SDLK_WORLD_2, "w2", "" },
+ { SDLK_WORLD_3, "w3", "" },
+ { SDLK_WORLD_4, "w4", "" },
+ { SDLK_WORLD_5, "w5", "" },
+ { SDLK_WORLD_6, "w6", "" },
+ { SDLK_WORLD_7, "w7", "" },
+ { SDLK_WORLD_8, "w8", "" },
+ { SDLK_WORLD_9, "w9", "" },
+ { SDLK_WORLD_10, "w10", "" },
+ { SDLK_WORLD_11, "w11", "" },
+ { SDLK_WORLD_12, "w12", "" },
+ { SDLK_WORLD_13, "w13", "" },
+ { SDLK_WORLD_14, "w14", "" },
+ { SDLK_WORLD_15, "w15", "" },
+ { SDLK_WORLD_16, "w16", "" },
+ { SDLK_WORLD_17, "w17", "" },
+ { SDLK_WORLD_18, "w18", "" },
+ { SDLK_WORLD_19, "w19", "" },
+ { SDLK_WORLD_20, "w20", "" },
+ { SDLK_WORLD_21, "w21", "" },
+ { SDLK_WORLD_22, "w22", "" },
+ { SDLK_WORLD_23, "w23", "" },
+ { SDLK_WORLD_24, "w24", "" },
+ { SDLK_WORLD_25, "w25", "" },
+ { SDLK_WORLD_26, "w26", "" },
+ { SDLK_WORLD_27, "w27", "" },
+ { SDLK_WORLD_28, "w28", "" },
+ { SDLK_WORLD_29, "w29", "" },
+ { SDLK_WORLD_30, "w30", "" },
+ { SDLK_WORLD_31, "w31", "" },
+ { SDLK_WORLD_32, "w32", "" },
+ { SDLK_WORLD_33, "w33", "" },
+ { SDLK_WORLD_34, "w34", "" },
+ { SDLK_WORLD_35, "w35", "" },
+ { SDLK_WORLD_36, "w36", "" },
+ { SDLK_WORLD_37, "w37", "" },
+ { SDLK_WORLD_38, "w38", "" },
+ { SDLK_WORLD_39, "w39", "" },
+ { SDLK_WORLD_40, "w40", "" },
+ { SDLK_WORLD_41, "w41", "" },
+ { SDLK_WORLD_42, "w42", "" },
+ { SDLK_WORLD_43, "w43", "" },
+ { SDLK_WORLD_44, "w44", "" },
+ { SDLK_WORLD_45, "w45", "" },
+ { SDLK_WORLD_46, "w46", "" },
+ { SDLK_WORLD_47, "w47", "" },
+ { SDLK_WORLD_48, "w48", "" },
+ { SDLK_WORLD_49, "w49", "" },
+ { SDLK_WORLD_50, "w50", "" },
+ { SDLK_WORLD_51, "w51", "" },
+ { SDLK_WORLD_52, "w52", "" },
+ { SDLK_WORLD_53, "w53", "" },
+ { SDLK_WORLD_54, "w54", "" },
+ { SDLK_WORLD_55, "w55", "" },
+ { SDLK_WORLD_56, "w56", "" },
+ { SDLK_WORLD_57, "w57", "" },
+ { SDLK_WORLD_58, "w58", "" },
+ { SDLK_WORLD_59, "w59", "" },
+ { SDLK_WORLD_60, "w60", "" },
+ { SDLK_WORLD_61, "w61", "" },
+ { SDLK_WORLD_62, "w62", "" },
+ { SDLK_WORLD_63, "w63", "" },
+ { SDLK_WORLD_64, "w64", "" },
+ { SDLK_WORLD_65, "w65", "" },
+ { SDLK_WORLD_66, "w66", "" },
+ { SDLK_WORLD_67, "w67", "" },
+ { SDLK_WORLD_68, "w68", "" },
+ { SDLK_WORLD_69, "w69", "" },
+ { SDLK_WORLD_70, "w70", "" },
+ { SDLK_WORLD_71, "w71", "" },
+ { SDLK_WORLD_72, "w72", "" },
+ { SDLK_WORLD_73, "w73", "" },
+ { SDLK_WORLD_74, "w74", "" },
+ { SDLK_WORLD_75, "w75", "" },
+ { SDLK_WORLD_76, "w76", "" },
+ { SDLK_WORLD_77, "w77", "" },
+ { SDLK_WORLD_78, "w78", "" },
+ { SDLK_WORLD_79, "w79", "" },
+ { SDLK_WORLD_80, "w80", "" },
+ { SDLK_WORLD_81, "w81", "" },
+ { SDLK_WORLD_82, "w82", "" },
+ { SDLK_WORLD_83, "w83", "" },
+ { SDLK_WORLD_84, "w84", "" },
+ { SDLK_WORLD_85, "w85", "" },
+ { SDLK_WORLD_86, "w86", "" },
+ { SDLK_WORLD_87, "w87", "" },
+ { SDLK_WORLD_88, "w88", "" },
+ { SDLK_WORLD_89, "w89", "" },
+ { SDLK_WORLD_90, "w90", "" },
+ { SDLK_WORLD_91, "w91", "" },
+ { SDLK_WORLD_92, "w92", "" },
+ { SDLK_WORLD_93, "w93", "" },
+ { SDLK_WORLD_94, "w94", "" },
+ { SDLK_WORLD_95, "w95", "" },
+#endif
+ /* Numeric keypad */
+ { SDLK_KP0, "KP0", "0" },
+ { SDLK_KP1, "KP1", "1" },
+ { SDLK_KP2, "KP2", "2" },
+ { SDLK_KP3, "KP3", "3" },
+ { SDLK_KP4, "KP4", "4" },
+ { SDLK_KP5, "KP5", "5" },
+ { SDLK_KP6, "KP6", "6" },
+ { SDLK_KP7, "KP7", "7" },
+ { SDLK_KP8, "KP8", "8" },
+ { SDLK_KP9, "KP9", "9" },
+ { SDLK_KP_PERIOD, "period", "." },
+ { SDLK_KP_DIVIDE, "KP_Divide", "/" },
+ { SDLK_KP_MULTIPLY, "KP_Multiply", "*" },
+ { SDLK_KP_MINUS, "KP_Minus", "-" },
+ { SDLK_KP_PLUS, "KP_Plus", "+" },
+ { SDLK_KP_ENTER, "KP_Enter", "\015" },
+ { SDLK_KP_EQUALS, "KP_Equals", "=" },
+
+ /* Arrows + Home/End pad */
+ { SDLK_UP, "Up", "Up" },
+ { SDLK_DOWN, "Down", "Down" },
+ { SDLK_RIGHT, "Right", "Right" },
+ { SDLK_LEFT, "Left", "Left" },
+ { SDLK_INSERT, "Insert", "Insert" },
+ { SDLK_HOME, "Home", "Home" },
+ { SDLK_END, "End", "End" },
+ { SDLK_PAGEUP, "Page_Up", "Page_Up" },
+ { SDLK_PAGEDOWN, "Page_Down", "Page_Down" },
+
+ /* Function keys */
+ { SDLK_F1, "F1", "F1" },
+ { SDLK_F2, "F2", "F2" },
+ { SDLK_F3, "F3", "F3" },
+ { SDLK_F4, "F4", "F4" },
+ { SDLK_F5, "F5", "F5" },
+ { SDLK_F6, "F6", "F6" },
+ { SDLK_F7, "F7", "F7" },
+ { SDLK_F8, "F8", "F8" },
+ { SDLK_F9, "F9", "F9" },
+ { SDLK_F10, "F10", "F10" },
+ { SDLK_F11, "F11", "F11" },
+ { SDLK_F12, "F12", "F12" },
+ { SDLK_F13, "F13", "F13" },
+ { SDLK_F14, "F14", "F14" },
+ { SDLK_F15, "F15", "F15" },
+
+ /* Key state modifier keys */
+ { SDLK_NUMLOCK, "Num_Lock", "Num_Lock" },
+ { SDLK_CAPSLOCK, "Caps_Lock", "Caps_Lock" },
+ { SDLK_SCROLLOCK, "Scroll_Lock", "Scroll_Lock" },
+ { SDLK_RSHIFT, "Shift_R", "Shift_R" },
+ { SDLK_LSHIFT, "Shift_L", "Shift_L" },
+ { SDLK_RCTRL, "Control_R", "Control_R" },
+ { SDLK_LCTRL, "Control_L", "Control_L" },
+ { SDLK_RALT, "Alt_R", "Alt_R" },
+ { SDLK_LALT, "Alt_L", "Alt_L" },
+ { SDLK_RMETA, "Meta_R", "Meta_R" },
+ { SDLK_LMETA, "Meta_L", "Meta_L" },
+ { SDLK_LSUPER, "Super_L", "Super_L" }, /* Left "Windows" key */
+ { SDLK_RSUPER, "Super_R", "Super_R" }, /* Right "Windows" key */
+ { SDLK_MODE, "Mode", "Mode" }, /* "Alt Gr" key */
+ { SDLK_COMPOSE, "Compose", "Compose" }, /* Multi-key compose key */
+
+ /* Miscellaneous function keys */
+ { SDLK_HELP, "Help", "Help" },
+ { SDLK_PRINT, "Print", "Print" },
+ { SDLK_SYSREQ, "SysReq", "SysReq" },
+ { SDLK_BREAK, "Break", "Break" },
+ { SDLK_MENU, "Menu", "Menu" },
+ { SDLK_POWER, "Power", "Power" }, /* Power Macintosh power key */
+ { SDLK_EURO, "Euro", "\200" }, /* Some european keyboards */
+ { SDLK_UNDO, "Undo", "Undo" } /* Atari keyboard has Undo */
+};
+
+#endif /* ECORE_SDL_KEYS_H__ */
diff --git a/src/lib/ecore_sdl/ecore_sdl.c b/src/lib/ecore_sdl/ecore_sdl.c
new file mode 100644
index 0000000000..f4a8faedb0
--- /dev/null
+++ b/src/lib/ecore_sdl/ecore_sdl.c
@@ -0,0 +1,334 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <SDL/SDL.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <ecore_private.h>
+#include <Ecore_Input.h>
+#include "Ecore_Sdl.h"
+#include "Ecore_Sdl_Keys.h"
+#include "ecore_sdl_private.h"
+
+
+int _ecore_sdl_log_dom = -1;
+
+typedef struct _Ecore_SDL_Pressed Ecore_SDL_Pressed;
+struct _Ecore_SDL_Pressed
+{
+ EINA_RBTREE;
+
+ SDLKey key;
+};
+
+EAPI int ECORE_SDL_EVENT_GOT_FOCUS = 0;
+EAPI int ECORE_SDL_EVENT_LOST_FOCUS = 0;
+EAPI int ECORE_SDL_EVENT_RESIZE = 0;
+EAPI int ECORE_SDL_EVENT_EXPOSE = 0;
+
+static int _ecore_sdl_init_count = 0;
+static Eina_Rbtree *repeat = NULL;
+
+static Eina_Rbtree_Direction
+_ecore_sdl_pressed_key(const Ecore_SDL_Pressed *left,
+ const Ecore_SDL_Pressed *right,
+ EINA_UNUSED void *data)
+{
+ return left->key < right->key ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
+}
+
+static int
+_ecore_sdl_pressed_node(const Ecore_SDL_Pressed *node,
+ const SDLKey *key,
+ EINA_UNUSED int length,
+ EINA_UNUSED void *data)
+{
+ return node->key - *key;
+}
+
+/**
+ * @defgroup Ecore_Sdl_Library_Group SDL Library Functions
+ *
+ * Functions used to set up and shut down the Ecore_Sdl functions.
+ */
+
+/**
+ * Sets up the Ecore_Sdl library.
+ * @param name device target name
+ * @return @c 0 on failure. Otherwise, the number of times the library has
+ * been initialised without being shut down.
+ * @ingroup Ecore_SDL_Library_Group
+ */
+EAPI int
+ecore_sdl_init(const char *name EINA_UNUSED)
+{
+ if(++_ecore_sdl_init_count != 1)
+ return _ecore_sdl_init_count;
+ _ecore_sdl_log_dom = eina_log_domain_register
+ ("ecore_sdl", ECORE_SDL_DEFAULT_LOG_COLOR);
+ if(_ecore_sdl_log_dom < 0)
+ {
+ EINA_LOG_ERR("Impossible to create a log domain for the Ecore SDL module.");
+ return --_ecore_sdl_init_count;
+ }
+ if (!ecore_event_init())
+ return --_ecore_sdl_init_count;
+
+ ECORE_SDL_EVENT_GOT_FOCUS = ecore_event_type_new();
+ ECORE_SDL_EVENT_LOST_FOCUS = ecore_event_type_new();
+ ECORE_SDL_EVENT_RESIZE = ecore_event_type_new();
+ ECORE_SDL_EVENT_EXPOSE = ecore_event_type_new();
+
+ SDL_EnableKeyRepeat(200, 100);
+
+ return _ecore_sdl_init_count;
+}
+
+/**
+ * Shuts down the Ecore_Sdl library.
+ * @return @c The number of times the system has been initialised without
+ * being shut down.
+ * @ingroup Ecore_SDL_Library_Group
+ */
+EAPI int
+ecore_sdl_shutdown(void)
+{
+ if (--_ecore_sdl_init_count != 0)
+ return _ecore_sdl_init_count;
+
+ ecore_event_shutdown();
+ eina_log_domain_unregister(_ecore_sdl_log_dom);
+ _ecore_sdl_log_dom = -1;
+ return _ecore_sdl_init_count;
+}
+
+static unsigned int
+_ecore_sdl_event_modifiers(int mod)
+{
+ unsigned int modifiers = 0;
+
+ if(mod & KMOD_LSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if(mod & KMOD_RSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if(mod & KMOD_LCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if(mod & KMOD_RCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if(mod & KMOD_LALT) modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ if(mod & KMOD_RALT) modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ if(mod & KMOD_NUM) modifiers |= ECORE_EVENT_LOCK_NUM;
+ if(mod & KMOD_CAPS) modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ return modifiers;
+}
+
+static Ecore_Event_Key*
+_ecore_sdl_event_key(SDL_Event *event, double timestamp)
+{
+ Ecore_Event_Key *ev;
+ unsigned int i;
+
+ ev = malloc(sizeof(Ecore_Event_Key));
+ if (!ev) return NULL;
+
+ ev->timestamp = timestamp;
+ ev->window = 0;
+ ev->event_window = 0;
+ ev->modifiers = _ecore_sdl_event_modifiers(SDL_GetModState());
+ ev->key = NULL;
+ ev->compose = NULL;
+
+ for (i = 0; i < sizeof(keystable) / sizeof(struct _ecore_sdl_keys_s); ++i)
+ if (keystable[i].code == event->key.keysym.sym)
+ {
+ ev->keyname = keystable[i].name;
+ ev->string = keystable[i].compose;
+
+ return ev;
+ }
+
+ free(ev);
+ return NULL;
+}
+
+EAPI void
+ecore_sdl_feed_events(void)
+{
+ SDL_Event event;
+ unsigned int timestamp;
+
+ while(SDL_PollEvent(&event))
+ {
+ timestamp = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff);
+ switch(event.type)
+ {
+ case SDL_MOUSEMOTION:
+ {
+ Ecore_Event_Mouse_Move *ev;
+
+ ev = malloc(sizeof(Ecore_Event_Mouse_Move));
+ if (!ev) return ;
+
+ ev->timestamp = timestamp;
+ ev->window = 0;
+ ev->event_window = 0;
+ ev->modifiers = 0; /* FIXME: keep modifier around. */
+ ev->x = event.motion.x;
+ ev->y = event.motion.y;
+ ev->root.x = ev->x;
+ ev->root.y = ev->y;
+
+ /* Must set multi touch device to 0 or it will get ignored */
+ ev->multi.device = 0;
+ ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
+ ev->multi.pressure = ev->multi.angle = 0;
+ ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+ break;
+ }
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ if (event.button.button == SDL_BUTTON_WHEELUP ||
+ event.button.button == SDL_BUTTON_WHEELDOWN)
+ {
+ Ecore_Event_Mouse_Wheel *ev;
+
+ ev = malloc(sizeof(Ecore_Event_Mouse_Wheel));
+ if (!ev) return ;
+
+ ev->timestamp = timestamp;
+ ev->window = 0;
+ ev->event_window = 0;
+ ev->modifiers = 0; /* FIXME: keep modifier around. */
+ ev->direction = 0;
+ ev->z = event.button.button == SDL_BUTTON_WHEELDOWN ? -1 : 1;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
+ }
+ else
+ {
+ Ecore_Event_Mouse_Button *ev;
+
+ ev = malloc(sizeof(Ecore_Event_Mouse_Button));
+ if (!ev) return ;
+
+ ev->timestamp = timestamp;
+ ev->window = 0;
+ ev->event_window = 0;
+ ev->modifiers = 0; /* FIXME: keep modifier around. */
+ ev->buttons = event.button.button;
+ ev->double_click = 0;
+ ev->triple_click = 0;
+
+ /* Must set multi touch device to 0 or it will get ignored */
+ ev->multi.device = 0;
+ ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
+ ev->multi.pressure = ev->multi.angle = 0;
+ ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+ }
+ break;
+ }
+ case SDL_MOUSEBUTTONUP:
+ {
+ Ecore_Event_Mouse_Button *ev;
+
+ ev = malloc(sizeof(Ecore_Event_Mouse_Button));
+ if (!ev) return ;
+ ev->timestamp = timestamp;
+ ev->window = 0;
+ ev->event_window = 0;
+ ev->modifiers = 0; /* FIXME: keep modifier around. */
+ ev->buttons = event.button.button;
+ ev->double_click = 0;
+ ev->triple_click = 0;
+
+ /* Must set multi touch device to 0 or it will get ignored */
+ ev->multi.device = 0;
+ ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
+ ev->multi.pressure = ev->multi.angle = 0;
+ ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+ break;
+ }
+ case SDL_VIDEORESIZE:
+ {
+ Ecore_Sdl_Event_Video_Resize *ev;
+
+ ev = malloc(sizeof (Ecore_Sdl_Event_Video_Resize));
+ ev->w = event.resize.w;
+ ev->h = event.resize.h;
+
+ ecore_event_add(ECORE_SDL_EVENT_RESIZE, ev, NULL, NULL);
+ break;
+ }
+ case SDL_VIDEOEXPOSE:
+ ecore_event_add(ECORE_SDL_EVENT_EXPOSE, NULL, NULL, NULL);
+ break;
+ case SDL_QUIT:
+ ecore_main_loop_quit();
+ break;
+
+ case SDL_KEYDOWN:
+ {
+ Ecore_SDL_Pressed *entry;
+ Ecore_Event_Key *ev;
+
+ entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym),
+ EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL);
+ if (entry)
+ {
+ ev = _ecore_sdl_event_key(&event, timestamp);
+ if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
+ }
+
+ ev = _ecore_sdl_event_key(&event, timestamp);
+ if (ev) ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL);
+
+ if (!entry)
+ {
+ entry = malloc(sizeof (Ecore_SDL_Pressed));
+ if (!entry) break;
+
+ entry->key = event.key.keysym.sym;
+
+ repeat = eina_rbtree_inline_insert(repeat, EINA_RBTREE_GET(entry),
+ EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL);
+ }
+ break;
+ }
+ case SDL_KEYUP:
+ {
+ Ecore_Event_Key *ev;
+ Ecore_SDL_Pressed *entry;
+
+ entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym),
+ EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL);
+ if (entry)
+ {
+ repeat = eina_rbtree_inline_remove(repeat, EINA_RBTREE_GET(entry),
+ EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL);
+ free(entry);
+ }
+
+ ev = _ecore_sdl_event_key(&event, timestamp);
+ if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
+ break;
+ }
+ case SDL_ACTIVEEVENT:
+ /* FIXME: Focus gain. */
+ break;
+ case SDL_SYSWMEVENT:
+ case SDL_USEREVENT:
+ case SDL_JOYAXISMOTION:
+ case SDL_JOYBALLMOTION:
+ case SDL_JOYHATMOTION:
+ case SDL_JOYBUTTONDOWN:
+ case SDL_JOYBUTTONUP:
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/lib/ecore_sdl/ecore_sdl_private.h b/src/lib/ecore_sdl/ecore_sdl_private.h
new file mode 100644
index 0000000000..37e957015d
--- /dev/null
+++ b/src/lib/ecore_sdl/ecore_sdl_private.h
@@ -0,0 +1,36 @@
+#ifndef _ECORE_SDL_PRIVATE_H
+# define _ECORE_SDL_PRIVATE_H
+
+extern int _ecore_sdl_log_dom;
+
+# ifdef ECORE_SDL_DEFAULT_LOG_COLOR
+# undef ECORE_SDL_DEFAULT_LOG_COLOR
+# endif
+# define ECORE_SDL_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+# ifdef ERR
+# undef ERR
+# endif
+# define ERR(...) EINA_LOG_DOM_ERR(_ecore_sdl_log_dom, __VA_ARGS__)
+
+# ifdef DBG
+# undef DBG
+# endif
+# define DBG(...) EINA_LOG_DOM_DBG(_ecore_sdl_log_dom, __VA_ARGS__)
+
+# ifdef INF
+# undef INF
+# endif
+# define INF(...) EINA_LOG_DOM_INFO(_ecore_sdl_log_dom, __VA_ARGS__)
+
+# ifdef WRN
+# undef WRN
+# endif
+# define WRN(...) EINA_LOG_DOM_WARN(_ecore_sdl_log_dom, __VA_ARGS__)
+
+# ifdef CRIT
+# undef CRIT
+# endif
+# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_sdl_log_dom, __VA_ARGS__)
+
+#endif
diff --git a/src/lib/ecore_wayland/Ecore_Wayland.h b/src/lib/ecore_wayland/Ecore_Wayland.h
new file mode 100644
index 0000000000..5281c6f8f3
--- /dev/null
+++ b/src/lib/ecore_wayland/Ecore_Wayland.h
@@ -0,0 +1,392 @@
+#ifndef _ECORE_WAYLAND_H_
+# define _ECORE_WAYLAND_H_
+
+/*
+ * Wayland supoprt is considered experimental as wayland itself is still
+ * unstable and liable to change core protocol. If you use this api, it is
+ * possible it will break in future, until this notice is removed.
+ */
+
+# include <Eina.h>
+# include <wayland-client.h>
+# include <wayland-cursor.h>
+# include <xkbcommon/xkbcommon.h>
+
+# ifdef EAPI
+# undef EAPI
+# endif
+
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+
+typedef enum _Ecore_Wl_Window_Type Ecore_Wl_Window_Type;
+typedef enum _Ecore_Wl_Window_Buffer_Type Ecore_Wl_Window_Buffer_Type;
+
+typedef struct _Ecore_Wl_Display Ecore_Wl_Display;
+typedef struct _Ecore_Wl_Output Ecore_Wl_Output;
+typedef struct _Ecore_Wl_Input Ecore_Wl_Input;
+# ifndef _ECORE_WAYLAND_WINDOW_PREDEF
+typedef struct _Ecore_Wl_Window Ecore_Wl_Window;
+# endif
+typedef struct _Ecore_Wl_Dnd Ecore_Wl_Dnd; /** @since 1.7 */
+typedef struct _Ecore_Wl_Dnd_Source Ecore_Wl_Dnd_Source;
+typedef struct _Ecore_Wl_Dnd_Target Ecore_Wl_Dnd_Target;
+
+typedef struct _Ecore_Wl_Event_Mouse_In Ecore_Wl_Event_Mouse_In;
+typedef struct _Ecore_Wl_Event_Mouse_Out Ecore_Wl_Event_Mouse_Out;
+typedef struct _Ecore_Wl_Event_Focus_In Ecore_Wl_Event_Focus_In;
+typedef struct _Ecore_Wl_Event_Focus_Out Ecore_Wl_Event_Focus_Out;
+typedef struct _Ecore_Wl_Event_Window_Configure Ecore_Wl_Event_Window_Configure;
+typedef struct _Ecore_Wl_Event_Dnd_Enter Ecore_Wl_Event_Dnd_Enter;
+typedef struct _Ecore_Wl_Event_Dnd_Position Ecore_Wl_Event_Dnd_Position;
+typedef struct _Ecore_Wl_Event_Dnd_Leave Ecore_Wl_Event_Dnd_Leave;
+typedef struct _Ecore_Wl_Event_Dnd_Drop Ecore_Wl_Event_Dnd_Drop;
+typedef struct _Ecore_Wl_Event_Data_Source_Send Ecore_Wl_Event_Data_Source_Send; /** @since 1.7 */
+typedef struct _Ecore_Wl_Event_Selection_Data_Ready Ecore_Wl_Event_Selection_Data_Ready; /** @since 1.7 */
+typedef struct _Ecore_Wl_Event_Interfaces_Bound Ecore_Wl_Event_Interfaces_Bound;
+
+enum _Ecore_Wl_Window_Type
+{
+ ECORE_WL_WINDOW_TYPE_NONE,
+ ECORE_WL_WINDOW_TYPE_TOPLEVEL,
+ ECORE_WL_WINDOW_TYPE_FULLSCREEN,
+ ECORE_WL_WINDOW_TYPE_MAXIMIZED,
+ ECORE_WL_WINDOW_TYPE_TRANSIENT,
+ ECORE_WL_WINDOW_TYPE_MENU,
+ ECORE_WL_WINDOW_TYPE_CUSTOM
+};
+
+enum _Ecore_Wl_Window_Buffer_Type
+{
+ ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW,
+ ECORE_WL_WINDOW_BUFFER_TYPE_EGL_IMAGE,
+ ECORE_WL_WINDOW_BUFFER_TYPE_SHM
+};
+
+struct _Ecore_Wl_Display
+{
+ struct
+ {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_shell *shell;
+ struct wl_shell *desktop_shell;
+ struct wl_shm *shm;
+ struct wl_data_device_manager *data_device_manager;
+ } wl;
+
+ int fd;
+ unsigned int mask;
+ unsigned int serial;
+ Ecore_Fd_Handler *fd_hdl;
+
+ struct wl_list inputs;
+ struct wl_list outputs;
+
+ struct
+ {
+ struct xkb_context *context;
+ } xkb;
+
+ struct wl_cursor_theme *cursor_theme;
+
+ Ecore_Wl_Output *output;
+ Ecore_Wl_Input *input;
+
+ void (*output_configure)(Ecore_Wl_Output *output, void *data);
+ void *data;
+};
+
+struct _Ecore_Wl_Output
+{
+ Ecore_Wl_Display *display;
+ struct wl_output *output;
+ Eina_Rectangle allocation;
+ int mw, mh;
+ struct wl_list link;
+
+ void (*destroy) (Ecore_Wl_Output *output, void *data);
+ void *data;
+};
+
+struct _Ecore_Wl_Input
+{
+ Ecore_Wl_Display *display;
+ struct wl_seat *seat;
+ struct wl_pointer *pointer;
+ struct wl_keyboard *keyboard;
+ struct wl_touch *touch;
+
+ const char *cursor_name;
+ struct wl_surface *cursor_surface;
+ struct wl_callback *cursor_frame_cb;
+
+ struct wl_data_device *data_device;
+
+ Ecore_Wl_Window *pointer_focus;
+ Ecore_Wl_Window *keyboard_focus;
+
+ unsigned int button;
+ unsigned int timestamp;
+ unsigned int modifiers;
+ unsigned int pointer_enter_serial;
+ int sx, sy;
+
+ struct wl_list link;
+
+ Ecore_Wl_Window *grab;
+ unsigned int grab_button;
+
+ Ecore_Wl_Dnd_Source *drag_source;
+ Ecore_Wl_Dnd_Source *selection_source;
+ Ecore_Wl_Dnd *dnd; /** @since 1.7 */
+
+ struct
+ {
+ struct xkb_keymap *keymap;
+ struct xkb_state *state;
+ xkb_mod_mask_t control_mask;
+ xkb_mod_mask_t alt_mask;
+ xkb_mod_mask_t shift_mask;
+ } xkb;
+
+ struct
+ {
+ Ecore_Fd_Handler *hdlr;
+ int timerfd;
+ unsigned int sym, key, time;
+ } repeat;
+};
+
+struct _Ecore_Wl_Window
+{
+ Ecore_Wl_Display *display;
+ Ecore_Wl_Window *parent;
+
+ struct wl_surface *surface;
+ struct wl_shell_surface *shell_surface;
+
+ struct
+ {
+ struct wl_region *input, *opaque;
+ } region;
+
+ int id;
+ int x, y;
+ int edges;
+
+ Eina_Rectangle allocation, pending_allocation;
+ Eina_Rectangle saved_allocation, server_allocation;
+
+ /* Eina_Bool redraw_scheduled : 1; */
+ /* Eina_Bool resize_scheduled : 1; */
+ Eina_Bool alpha : 1;
+ Eina_Bool transparent : 1;
+ Eina_Bool moving : 1;
+ Eina_Bool resizing : 1;
+
+ Ecore_Wl_Window_Type type;
+ Ecore_Wl_Window_Buffer_Type buffer_type;
+
+ Ecore_Wl_Input *pointer_device;
+ Ecore_Wl_Input *keyboard_device;
+
+ Eina_Bool frame_pending;
+ struct wl_callback *frame_callback;
+ /* FIXME: Ideally we should record the cursor name for this window
+ * so we can compare and avoid unnecessary cursor set calls to wayland */
+
+ void *data;
+};
+
+struct _Ecore_Wl_Event_Mouse_In
+{
+ int modifiers;
+ int x, y;
+ struct
+ {
+ int x, y;
+ } root;
+ unsigned int window;
+ unsigned int event_window;
+ unsigned int root_window;
+ unsigned int timestamp;
+};
+
+struct _Ecore_Wl_Event_Mouse_Out
+{
+ int modifiers;
+ int x, y;
+ struct
+ {
+ int x, y;
+ } root;
+ unsigned int window;
+ unsigned int event_window;
+ unsigned int root_window;
+ unsigned int timestamp;
+};
+
+struct _Ecore_Wl_Event_Focus_In
+{
+ unsigned int win;
+ unsigned int timestamp;
+};
+
+struct _Ecore_Wl_Event_Focus_Out
+{
+ unsigned int win;
+ unsigned int timestamp;
+};
+
+struct _Ecore_Wl_Event_Window_Configure
+{
+ unsigned int win;
+ unsigned int event_win;
+ int x, y, w, h;
+};
+
+struct _Ecore_Wl_Event_Dnd_Enter
+{
+ unsigned int win, source;
+ char **types;
+ int num_types;
+ struct
+ {
+ int x, y;
+ } position;
+};
+
+struct _Ecore_Wl_Event_Dnd_Position
+{
+ unsigned int win, source;
+ struct
+ {
+ int x, y;
+ } position;
+};
+
+struct _Ecore_Wl_Event_Dnd_Leave
+{
+ unsigned int win, source;
+};
+
+struct _Ecore_Wl_Event_Dnd_Drop
+{
+ unsigned int win, source;
+ struct
+ {
+ int x, y;
+ } position;
+};
+
+/** @since 1.7 */
+struct _Ecore_Wl_Event_Data_Source_Send
+{
+ char *type;
+ int fd;
+};
+
+/** @since 1.7 */
+struct _Ecore_Wl_Event_Selection_Data_Ready
+{
+ char *data;
+ int len;
+ Eina_Bool done;
+};
+
+struct _Ecore_Wl_Event_Interfaces_Bound
+{
+ Eina_Bool compositor : 1;
+ Eina_Bool shm : 1;
+ Eina_Bool shell : 1;
+};
+
+/**
+ * @file
+ * @brief Ecore functions for dealing with the Wayland window system
+ *
+ * Ecore_Wl provides a wrapper and convenience functions for using the
+ * Wayland window system. Function groups for this part of the library
+ * include the following:
+ *
+ * @li @ref Ecore_Wl_Init_Group
+ * @li @ref Ecore_Wl_Display_Group
+ * @li @ref Ecore_Wl_Flush_Group
+ * @li @ref Ecore_Wl_Window_Group
+ */
+
+EAPI extern int ECORE_WL_EVENT_MOUSE_IN;
+EAPI extern int ECORE_WL_EVENT_MOUSE_OUT;
+EAPI extern int ECORE_WL_EVENT_FOCUS_IN;
+EAPI extern int ECORE_WL_EVENT_FOCUS_OUT;
+EAPI extern int ECORE_WL_EVENT_WINDOW_CONFIGURE;
+EAPI extern int ECORE_WL_EVENT_DND_ENTER;
+EAPI extern int ECORE_WL_EVENT_DND_POSITION;
+EAPI extern int ECORE_WL_EVENT_DND_LEAVE;
+EAPI extern int ECORE_WL_EVENT_DND_DROP;
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_TARGET; /** @since 1.7 */
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_SEND; /** @since 1.7 */
+EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED; /** @since 1.7 */
+EAPI extern int ECORE_WL_EVENT_SELECTION_DATA_READY; /** @since 1.7 */
+EAPI extern int ECORE_WL_EVENT_INTERFACES_BOUND;
+
+EAPI int ecore_wl_init(const char *name);
+EAPI int ecore_wl_shutdown(void);
+EAPI void ecore_wl_flush(void);
+EAPI void ecore_wl_sync(void);
+EAPI struct wl_shm *ecore_wl_shm_get(void);
+EAPI struct wl_display *ecore_wl_display_get(void);
+EAPI void ecore_wl_screen_size_get(int *w, int *h);
+EAPI void ecore_wl_pointer_xy_get(int *x, int *y);
+EAPI int ecore_wl_dpi_get(void);
+EAPI void ecore_wl_display_iterate(void);
+EAPI struct wl_cursor *ecore_wl_cursor_get(const char *cursor_name);
+
+EAPI void ecore_wl_input_grab(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int button);
+EAPI void ecore_wl_input_ungrab(Ecore_Wl_Input *input);
+EAPI void ecore_wl_input_pointer_set(Ecore_Wl_Input *input, struct wl_surface *surface, int hot_x, int hot_y);
+EAPI void ecore_wl_input_cursor_from_name_set(Ecore_Wl_Input *input, const char *cursor_name);
+EAPI void ecore_wl_input_cursor_default_restore(Ecore_Wl_Input *input);
+
+EAPI struct wl_list ecore_wl_outputs_get(void);
+
+EAPI Ecore_Wl_Window *ecore_wl_window_new(Ecore_Wl_Window *parent, int x, int y, int w, int h, int buffer_type);
+EAPI void ecore_wl_window_free(Ecore_Wl_Window *win);
+EAPI void ecore_wl_window_move(Ecore_Wl_Window *win, int x, int y);
+EAPI void ecore_wl_window_resize(Ecore_Wl_Window *win, int w, int h, int location);
+EAPI void ecore_wl_window_damage(Ecore_Wl_Window *win, int x, int y, int w, int h);
+EAPI void ecore_wl_window_buffer_attach(Ecore_Wl_Window *win, struct wl_buffer *buffer, int x, int y);
+EAPI void ecore_wl_window_show(Ecore_Wl_Window *win);
+EAPI void ecore_wl_window_hide(Ecore_Wl_Window *win);
+EAPI void ecore_wl_window_raise(Ecore_Wl_Window *win);
+EAPI void ecore_wl_window_maximized_set(Ecore_Wl_Window *win, Eina_Bool maximized);
+EAPI void ecore_wl_window_fullscreen_set(Ecore_Wl_Window *win, Eina_Bool fullscreen);
+EAPI void ecore_wl_window_transparent_set(Ecore_Wl_Window *win, Eina_Bool transparent);
+EAPI void ecore_wl_window_update_size(Ecore_Wl_Window *win, int w, int h);
+EAPI void ecore_wl_window_update_location(Ecore_Wl_Window *win, int x, int y);
+EAPI struct wl_surface *ecore_wl_window_surface_get(Ecore_Wl_Window *win);
+EAPI struct wl_shell_surface *ecore_wl_window_shell_surface_get(Ecore_Wl_Window *win);
+EAPI Ecore_Wl_Window *ecore_wl_window_find(unsigned int id);
+EAPI void ecore_wl_window_type_set(Ecore_Wl_Window *win, Ecore_Wl_Window_Type type);
+EAPI void ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *surface, int hot_x, int hot_y);
+EAPI void ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name);
+EAPI void ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win);
+EAPI void ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent);
+
+/** @since 1.7 */
+EAPI Eina_Bool ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered);
+EAPI Eina_Bool ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type);
+EAPI Ecore_Wl_Dnd *ecore_wl_dnd_get();
+EAPI Eina_Bool ecore_wl_dnd_start_drag();
+EAPI Eina_Bool ecore_wl_dnd_selection_has_owner(Ecore_Wl_Dnd *dnd);
+
+#endif
diff --git a/src/lib/ecore_wayland/ecore_wl.c b/src/lib/ecore_wayland/ecore_wl.c
new file mode 100644
index 0000000000..481ba790b6
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl.c
@@ -0,0 +1,497 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include "ecore_wl_private.h"
+
+/* local function prototypes */
+static Eina_Bool _ecore_wl_shutdown(Eina_Bool close);
+static Eina_Bool _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl);
+static void _ecore_wl_cb_handle_global(void *data, struct wl_registry *registry, unsigned int id, const char *interface, unsigned int version EINA_UNUSED);
+static Eina_Bool _ecore_wl_xkb_init(Ecore_Wl_Display *ewd);
+static Eina_Bool _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd);
+
+/* local variables */
+static int _ecore_wl_init_count = 0;
+static const struct wl_registry_listener _ecore_wl_registry_listener =
+{
+ _ecore_wl_cb_handle_global,
+ NULL // handle_global_remove
+};
+
+/* external variables */
+int _ecore_wl_log_dom = -1;
+Ecore_Wl_Display *_ecore_wl_disp = NULL;
+
+EAPI int ECORE_WL_EVENT_MOUSE_IN = 0;
+EAPI int ECORE_WL_EVENT_MOUSE_OUT = 0;
+EAPI int ECORE_WL_EVENT_FOCUS_IN = 0;
+EAPI int ECORE_WL_EVENT_FOCUS_OUT = 0;
+EAPI int ECORE_WL_EVENT_WINDOW_CONFIGURE = 0;
+EAPI int ECORE_WL_EVENT_DND_ENTER = 0;
+EAPI int ECORE_WL_EVENT_DND_POSITION = 0;
+EAPI int ECORE_WL_EVENT_DND_LEAVE = 0;
+EAPI int ECORE_WL_EVENT_DND_DROP = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_TARGET = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_SEND = 0;
+EAPI int ECORE_WL_EVENT_SELECTION_DATA_READY = 0;
+EAPI int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = 0;
+EAPI int ECORE_WL_EVENT_INTERFACES_BOUND = 0;
+
+/**
+ * @defgroup Ecore_Wl_Init_Group Wayland Library Init and Shutdown Functions
+ *
+ * Functions that start and shutdown the Ecore Wayland Library.
+ */
+
+/**
+ * Initialize the Wayland display connection to the given display.
+ *
+ * @param name Display target name. if @c NULL, the default display is
+ * assumed.
+ * @return The number of times the library has been initialized without being
+ * shut down. 0 is returned if an error occurs.
+ *
+ * @ingroup Ecore_Wl_Init_Group
+ */
+EAPI int
+ecore_wl_init(const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (++_ecore_wl_init_count != 1) return _ecore_wl_init_count;
+
+ if (!eina_init()) return --_ecore_wl_init_count;
+
+ _ecore_wl_log_dom =
+ eina_log_domain_register("ecore_wl", ECORE_WL_DEFAULT_LOG_COLOR);
+ if (_ecore_wl_log_dom < 0)
+ {
+ EINA_LOG_ERR("Cannot create a log domain for Ecore Wayland");
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ if (!ecore_init())
+ {
+ ERR("Could not initialize ecore");
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ if (!ecore_event_init())
+ {
+ ERR("Could not initialize ecore_event");
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ if (!ECORE_WL_EVENT_MOUSE_IN)
+ {
+ ECORE_WL_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_WL_EVENT_MOUSE_OUT = ecore_event_type_new();
+ ECORE_WL_EVENT_FOCUS_IN = ecore_event_type_new();
+ ECORE_WL_EVENT_FOCUS_OUT = ecore_event_type_new();
+ ECORE_WL_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
+ ECORE_WL_EVENT_DND_ENTER = ecore_event_type_new();
+ ECORE_WL_EVENT_DND_POSITION = ecore_event_type_new();
+ ECORE_WL_EVENT_DND_LEAVE = ecore_event_type_new();
+ ECORE_WL_EVENT_DND_DROP = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_TARGET = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_SEND = ecore_event_type_new();
+ ECORE_WL_EVENT_SELECTION_DATA_READY = ecore_event_type_new();
+ ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = ecore_event_type_new();
+ ECORE_WL_EVENT_INTERFACES_BOUND = ecore_event_type_new();
+ }
+
+ if (!(_ecore_wl_disp = malloc(sizeof(Ecore_Wl_Display))))
+ {
+ ERR("Could not allocate memory for Ecore_Wl_Display structure");
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ memset(_ecore_wl_disp, 0, sizeof(Ecore_Wl_Display));
+
+ if (!(_ecore_wl_disp->wl.display = wl_display_connect(name)))
+ {
+ ERR("Could not connect to Wayland display");
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ _ecore_wl_disp->fd = wl_display_get_fd(_ecore_wl_disp->wl.display);
+
+ _ecore_wl_disp->fd_hdl =
+ ecore_main_fd_handler_add(_ecore_wl_disp->fd,
+ ECORE_FD_READ | ECORE_FD_WRITE,
+ _ecore_wl_cb_handle_data, _ecore_wl_disp,
+ NULL, NULL);
+
+ wl_list_init(&_ecore_wl_disp->inputs);
+ wl_list_init(&_ecore_wl_disp->outputs);
+
+ _ecore_wl_disp->wl.registry =
+ wl_display_get_registry(_ecore_wl_disp->wl.display);
+ wl_registry_add_listener(_ecore_wl_disp->wl.registry,
+ &_ecore_wl_registry_listener, _ecore_wl_disp);
+
+ wl_display_dispatch(_ecore_wl_disp->wl.display);
+
+ if (!_ecore_wl_xkb_init(_ecore_wl_disp))
+ {
+ ERR("Could not initialize XKB");
+ free(_ecore_wl_disp);
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_wl_init_count;
+ }
+
+ _ecore_wl_window_init();
+
+ return _ecore_wl_init_count;
+}
+
+/**
+ * Shuts down the Ecore Wayland Library
+ *
+ * In shutting down the library, the Wayland display connection is terminated
+ * and any event handlers for it are removed.
+ *
+ * @return The number of times the library has been initialized without
+ * being shut down.
+ *
+ * @ingroup Ecore_Wl_Init_Group
+ */
+EAPI int
+ecore_wl_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_wl_shutdown(EINA_TRUE);
+}
+
+/**
+ * @defgroup Ecore_Wl_Flush_Group Wayland Synchronization Functions
+ *
+ * Functions that ensure that all commands which have been issued by the
+ * Ecore Wayland library have been sent to the server.
+ */
+
+/**
+ * Sends all Wayland commands to the Wayland Display.
+ *
+ * @ingroup Ecore_Wl_Flush_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_flush(void)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ wl_display_flush(_ecore_wl_disp->wl.display);
+}
+
+/**
+ * Flushes the command buffer and waits until all requests have been
+ * processed by the server.
+ *
+ * @ingroup Ecore_Wl_Flush_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_sync(void)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ wl_display_sync(_ecore_wl_disp->wl.display);
+}
+
+/**
+ * @defgroup Ecore_Wl_Display_Group Wayland Display Functions
+ *
+ * Functions that set and retrieve various information about the Wayland Display.
+ */
+
+/**
+ * Retrieves the Wayland Shm Interface used for the current Wayland connection.
+ *
+ * @return The current wayland shm interface
+ *
+ * @ingroup Ecore_Wl_Display_Group
+ * @since 1.2
+ */
+EAPI struct wl_shm *
+ecore_wl_shm_get(void)
+{
+ return _ecore_wl_disp->wl.shm;
+}
+
+/**
+ * Retrieves the Wayland Display Interface used for the current Wayland connection.
+ *
+ * @return The current wayland display interface
+ *
+ * @ingroup Ecore_Wl_Display_Group
+ * @since 1.2
+ */
+EAPI struct wl_display *
+ecore_wl_display_get(void)
+{
+ return _ecore_wl_disp->wl.display;
+}
+
+/**
+ * Retrieves the size of the current screen.
+ *
+ * @param w where to return the width. May be NULL. Returns 0 on error.
+ * @param h where to return the height. May be NULL. Returns 0 on error.
+ *
+ * @ingroup Ecore_Wl_Display_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_screen_size_get(int *w, int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ if (!_ecore_wl_disp->output) return;
+
+ if (w) *w = _ecore_wl_disp->output->allocation.w;
+ if (h) *h = _ecore_wl_disp->output->allocation.h;
+}
+
+/* @since 1.2 */
+EAPI void
+ecore_wl_pointer_xy_get(int *x, int *y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_input_pointer_xy_get(x, y);
+}
+
+/**
+ * Return the screen DPI
+ *
+ * This is a simplistic call to get DPI. It does not account for differing
+ * DPI in the x and y axes nor does it account for multihead or xinerama and
+ * xrandr where different parts of the screen may have different DPI etc.
+ *
+ * @return the general screen DPI (dots/pixels per inch).
+ *
+ * @since 1.2
+ */
+EAPI int
+ecore_wl_dpi_get(void)
+{
+ int w, mw;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!_ecore_wl_disp->output) return 75;
+
+ mw = _ecore_wl_disp->output->mw;
+ if (mw <= 0) return 75;
+
+ w = _ecore_wl_disp->output->allocation.w;
+ /* FIXME: NB: Hrrrmmm, need to verify this. xorg code is using a different
+ * formula to calc this */
+ return (((w * 254) / mw) + 5) / 10;
+}
+
+EAPI void
+ecore_wl_display_iterate(void)
+{
+ wl_display_dispatch(_ecore_wl_disp->wl.display);
+}
+
+/**
+ * Retrieves the requested cursor from the cursor theme
+ *
+ * @param cursor_name The desired cursor name to be looked up in the theme
+ * @return the cursor or NULL if the cursor cannot be found
+ *
+ * @since 1.2
+ */
+EAPI struct wl_cursor *
+ecore_wl_cursor_get(const char *cursor_name)
+{
+ if ((!_ecore_wl_disp) || (!_ecore_wl_disp->cursor_theme))
+ return NULL;
+
+ return wl_cursor_theme_get_cursor(_ecore_wl_disp->cursor_theme,
+ cursor_name);
+}
+
+/* local functions */
+static Eina_Bool
+_ecore_wl_shutdown(Eina_Bool close)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (--_ecore_wl_init_count != 0) return _ecore_wl_init_count;
+ if (!_ecore_wl_disp) return _ecore_wl_init_count;
+
+ _ecore_wl_window_shutdown();
+
+ if (_ecore_wl_disp->fd_hdl)
+ ecore_main_fd_handler_del(_ecore_wl_disp->fd_hdl);
+
+ if (close)
+ {
+ Ecore_Wl_Output *out, *tout;
+ Ecore_Wl_Input *in, *tin;
+
+ wl_list_for_each_safe(out, tout, &_ecore_wl_disp->outputs, link)
+ _ecore_wl_output_del(out);
+
+ wl_list_for_each_safe(in, tin, &_ecore_wl_disp->inputs, link)
+ _ecore_wl_input_del(in);
+
+ _ecore_wl_xkb_shutdown(_ecore_wl_disp);
+
+ if (_ecore_wl_disp->wl.shell)
+ wl_shell_destroy(_ecore_wl_disp->wl.shell);
+ if (_ecore_wl_disp->wl.shm) wl_shm_destroy(_ecore_wl_disp->wl.shm);
+ if (_ecore_wl_disp->wl.data_device_manager)
+ wl_data_device_manager_destroy(_ecore_wl_disp->wl.data_device_manager);
+ if (_ecore_wl_disp->wl.compositor)
+ wl_compositor_destroy(_ecore_wl_disp->wl.compositor);
+ if (_ecore_wl_disp->wl.display)
+ {
+ wl_registry_destroy(_ecore_wl_disp->wl.registry);
+ wl_display_flush(_ecore_wl_disp->wl.display);
+ wl_display_disconnect(_ecore_wl_disp->wl.display);
+ }
+ free(_ecore_wl_disp);
+ }
+
+ ecore_event_shutdown();
+ ecore_shutdown();
+
+ eina_log_domain_unregister(_ecore_wl_log_dom);
+ _ecore_wl_log_dom = -1;
+ eina_shutdown();
+
+ return _ecore_wl_init_count;
+}
+
+static Eina_Bool
+_ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl)
+{
+ Ecore_Wl_Display *ewd;
+
+ /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
+
+ if (!(ewd = data)) return ECORE_CALLBACK_RENEW;
+
+ /* FIXME: This should also catch ECORE_FD_ERROR and exit */
+
+ /* wl_display_dispatch_pending(ewd->wl.display); */
+
+ if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_READ))
+ wl_display_dispatch(ewd->wl.display);
+ else if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_WRITE))
+ wl_display_flush(ewd->wl.display);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_wl_cb_handle_global(void *data, struct wl_registry *registry, unsigned int id, const char *interface, unsigned int version EINA_UNUSED)
+{
+ Ecore_Wl_Display *ewd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ewd = data;
+
+ if (!strcmp(interface, "wl_compositor"))
+ {
+ ewd->wl.compositor =
+ wl_registry_bind(registry, id, &wl_compositor_interface, 1);
+ }
+ else if (!strcmp(interface, "wl_output"))
+ _ecore_wl_output_add(ewd, id);
+ else if (!strcmp(interface, "wl_seat"))
+ _ecore_wl_input_add(ewd, id);
+ else if (!strcmp(interface, "wl_shell"))
+ {
+ ewd->wl.shell =
+ wl_registry_bind(registry, id, &wl_shell_interface, 1);
+ }
+ else if (!strcmp(interface, "wl_shm"))
+ {
+ ewd->wl.shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+
+ /* FIXME: We should not hard-code a cursor size here, and we should
+ * also import the theme name from a config or env variable */
+ ewd->cursor_theme = wl_cursor_theme_load(NULL, 32, ewd->wl.shm);
+ }
+ else if (!strcmp(interface, "wl_data_device_manager"))
+ {
+ ewd->wl.data_device_manager =
+ wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1);
+ }
+
+ if ((ewd->wl.compositor) && (ewd->wl.shm) && (ewd->wl.shell))
+ {
+ Ecore_Wl_Event_Interfaces_Bound *ev;
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Interfaces_Bound))))
+ return;
+
+ ev->compositor = (ewd->wl.compositor != NULL);
+ ev->shm = (ewd->wl.shm != NULL);
+ ev->shell = (ewd->wl.shell != NULL);
+
+ ecore_event_add(ECORE_WL_EVENT_INTERFACES_BOUND, ev, NULL, NULL);
+ }
+}
+
+static Eina_Bool
+_ecore_wl_xkb_init(Ecore_Wl_Display *ewd)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ewd->xkb.context = xkb_context_new(0)))
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xkb_context_unref(ewd->xkb.context);
+
+ return EINA_TRUE;
+}
+
+struct wl_data_source *
+_ecore_wl_create_data_source(Ecore_Wl_Display *ewd)
+{
+ return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager);
+}
diff --git a/src/lib/ecore_wayland/ecore_wl_dnd.c b/src/lib/ecore_wayland/ecore_wl_dnd.c
new file mode 100644
index 0000000000..403e3b9f6b
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl_dnd.c
@@ -0,0 +1,485 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include "ecore_wl_private.h"
+
+struct _dnd_task
+{
+ void *data;
+ Ecore_Fd_Cb cb;
+};
+
+struct _dnd_read_ctx
+{
+ int epoll_fd;
+ struct epoll_event *ep;
+};
+
+/* local function prototypes */
+static void _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer EINA_UNUSED, const char *type);
+static void _ecore_wl_dnd_cb_enter_free(void *data EINA_UNUSED, void *event);
+
+static void _ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type);
+static void _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd);
+static void _ecore_wl_dnd_data_source_cancelled(void *data, struct wl_data_source *source);
+static void _ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type);
+
+/* wayland listeners */
+static const struct wl_data_offer_listener _ecore_wl_data_offer_listener =
+{
+ _ecore_wl_dnd_offer,
+};
+
+static const struct wl_data_source_listener _ecore_wl_data_source_listener =
+{
+ _ecore_wl_dnd_data_source_target,
+ _ecore_wl_dnd_data_source_send,
+ _ecore_wl_dnd_data_source_cancelled
+};
+
+extern Ecore_Wl_Dnd *glb_dnd;
+
+EAPI Ecore_Wl_Dnd *
+ecore_wl_dnd_get()
+{
+ return glb_dnd;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_start_drag(Ecore_Wl_Dnd *dnd EINA_UNUSED)
+{
+ //TODO:
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered)
+{
+ char **p;
+ const char **type;
+
+ dnd->data_source = _ecore_wl_create_data_source(dnd->ewd);
+
+ /* free old types */
+ if (dnd->types_offered.data)
+ {
+ wl_array_for_each(p, &dnd->types_offered)
+ free(*p);
+ wl_array_release(&dnd->types_offered);
+ wl_array_init(&dnd->types_offered);
+ }
+
+ for (type = types_offered; *type; type++)
+ {
+ p = wl_array_add(&dnd->types_offered, sizeof(*p));
+ *p = strdup(*type);
+ wl_data_source_offer(dnd->data_source, *p);
+ }
+
+ wl_data_source_add_listener(dnd->data_source, &_ecore_wl_data_source_listener, dnd);
+
+ _ecore_wl_input_set_selection(dnd->input, dnd->data_source);
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type)
+{
+ char **p;
+ Ecore_Wl_Input *input;
+
+ input = dnd->input;
+
+ if (!input->selection_source) return EINA_FALSE;
+
+ wl_array_for_each(p, &input->selection_source->types)
+ if (strcmp(type, *p) == 0) break;
+
+ if (!*p) return EINA_FALSE;
+
+ _ecore_wl_dnd_source_receive_data(input->selection_source, type);
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_wl_dnd_selection_has_owner(Ecore_Wl_Dnd *dnd)
+{
+ Ecore_Wl_Input *input;
+
+ input = dnd->input;
+ return (input->selection_source != NULL);
+}
+
+/* local functions */
+static void
+_ecore_wl_dnd_data_source_target(void *data EINA_UNUSED, struct wl_data_source *source EINA_UNUSED, const char *mime_type EINA_UNUSED)
+{
+ //TODO:
+}
+
+static void
+_ecore_wl_dnd_cb_data_source_send_free(void *data EINA_UNUSED, void *event)
+{
+ Ecore_Wl_Event_Data_Source_Send *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = event)) return;
+
+ free(ev->type);
+ free(ev);
+}
+
+static void
+_ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source EINA_UNUSED, const char *mime_type, int32_t fd)
+{
+ Ecore_Wl_Event_Data_Source_Send *event;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!data) return;
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Data_Source_Send)))) return;
+
+ event->type = strdup(mime_type);
+ event->fd = fd;
+
+ ecore_event_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, event, _ecore_wl_dnd_cb_data_source_send_free, NULL);
+}
+
+static void
+_ecore_wl_dnd_data_source_cancelled(void *data EINA_UNUSED, struct wl_data_source *source)
+{
+ wl_data_source_destroy(source);
+}
+
+void
+_ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device EINA_UNUSED, struct wl_data_offer *offer)
+{
+ Ecore_Wl_Dnd_Source *source;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(source = malloc(sizeof(Ecore_Wl_Dnd_Source)))) return;
+ wl_array_init(&source->types);
+ source->refcount = 1;
+ source->input = input;
+ source->offer = offer;
+ wl_data_offer_add_listener(source->offer,
+ &_ecore_wl_data_offer_listener, source);
+}
+
+void
+_ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device EINA_UNUSED, unsigned int timestamp EINA_UNUSED, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer)
+{
+ Ecore_Wl_Event_Dnd_Enter *event;
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win;
+ char **p;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!(input = data)) || (!offer)) return;
+
+ if (!(input->drag_source = wl_data_offer_get_user_data(offer)))
+ return;
+
+ win = wl_surface_get_user_data(surface);
+// input->pointer_focus = win;
+
+ p = wl_array_add(&input->drag_source->types, sizeof(*p));
+ *p = NULL;
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Enter)))) return;
+
+ event->win = win->id;
+ if (input->drag_source->input)
+ {
+ if (input->drag_source->input->keyboard_focus)
+ event->source = input->drag_source->input->keyboard_focus->id;
+ }
+
+ event->position.x = wl_fixed_to_int(x);
+ event->position.y = wl_fixed_to_int(y);
+ event->num_types = input->drag_source->types.size;
+ event->types = input->drag_source->types.data;
+
+ ecore_event_add(ECORE_WL_EVENT_DND_ENTER, event,
+ _ecore_wl_dnd_cb_enter_free, NULL);
+}
+
+void
+_ecore_wl_dnd_leave(void *data, struct wl_data_device *data_device EINA_UNUSED)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+ /* FIXME: NB: This MAY need to raise a wl_event_dnd_leave for the
+ * source window */
+ _ecore_wl_dnd_del(input->drag_source);
+ input->drag_source = NULL;
+}
+
+void
+_ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device EINA_UNUSED, unsigned int timestamp EINA_UNUSED, wl_fixed_t x, wl_fixed_t y)
+{
+ Ecore_Wl_Event_Dnd_Position *event;
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ input->sx = wl_fixed_to_int(x);
+ input->sy = wl_fixed_to_int(y);
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Position)))) return;
+
+ if (input->drag_source)
+ {
+ if (input->drag_source->input)
+ {
+ if (input->drag_source->input->pointer_focus)
+ event->win = input->drag_source->input->pointer_focus->id;
+ if (input->drag_source->input->keyboard_focus)
+ event->source = input->drag_source->input->keyboard_focus->id;
+ }
+ }
+
+ event->position.x = input->sx;
+ event->position.y = input->sy;
+
+ ecore_event_add(ECORE_WL_EVENT_DND_POSITION, event, NULL, NULL);
+}
+
+void
+_ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device EINA_UNUSED)
+{
+ Ecore_Wl_Event_Dnd_Drop *event;
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Drop)))) return;
+
+ if (input->drag_source)
+ {
+ if (input->drag_source->input)
+ {
+ if (input->drag_source->input->pointer_focus)
+ event->win = input->drag_source->input->pointer_focus->id;
+ if (input->drag_source->input->keyboard_focus)
+ event->source = input->drag_source->input->keyboard_focus->id;
+ }
+ }
+
+ event->position.x = input->sx;
+ event->position.y = input->sy;
+
+ ecore_event_add(ECORE_WL_EVENT_DND_DROP, event, NULL, NULL);
+}
+
+void
+_ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device EINA_UNUSED, struct wl_data_offer *offer)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+ if (input->selection_source) _ecore_wl_dnd_del(input->selection_source);
+ input->selection_source = NULL;
+ if (offer)
+ {
+ char **p;
+
+ input->selection_source = wl_data_offer_get_user_data(offer);
+ p = wl_array_add(&input->selection_source->types, sizeof(*p));
+ *p = NULL;
+ }
+}
+
+void
+_ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!source) return;
+ source->refcount--;
+ if (source->refcount == 0)
+ {
+ char **p;
+
+ wl_data_offer_destroy(source->offer);
+ for (p = source->types.data; *p; p++)
+ free(*p);
+ wl_array_release(&source->types);
+ free(source);
+ }
+}
+
+/* local functions */
+static void
+_ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer EINA_UNUSED, const char *type)
+{
+ Ecore_Wl_Dnd_Source *source;
+ char **p;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(source = data)) return;
+ p = wl_array_add(&source->types, sizeof(*p));
+ *p = strdup(type);
+}
+
+static void
+_ecore_wl_dnd_cb_enter_free(void *data EINA_UNUSED, void *event)
+{
+ Ecore_Wl_Event_Dnd_Enter *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = event)) return;
+ free(ev);
+}
+
+static void
+_ecore_wl_dnd_cb_selection_data_ready_free(void *data EINA_UNUSED, void *event)
+{
+ Ecore_Wl_Event_Selection_Data_Ready *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = event)) return;
+
+ free(ev->data);
+ free(ev);
+}
+
+static Eina_Bool
+_ecore_wl_dnd_read_data(void *data, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ int len;
+ char buffer[4096];
+ Ecore_Wl_Dnd_Source *source;
+ Ecore_Wl_Event_Selection_Data_Ready *event;
+ Eina_Bool ret;
+
+ source = data;
+
+ len = read(source->fd, buffer, sizeof buffer);
+
+ if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Selection_Data_Ready))))
+ return ECORE_CALLBACK_CANCEL;
+
+ if (len <= 0)
+ {
+ close(source->fd);
+ _ecore_wl_dnd_del(source);
+ event->done = EINA_TRUE;
+ event->data = NULL;
+ event->len = 0;
+ ret = ECORE_CALLBACK_CANCEL;
+ }
+ else
+ {
+ event->data = malloc(len + 1);
+ if (!event->data) return ECORE_CALLBACK_CANCEL;
+ strncpy(event->data, buffer, len);
+ event->data[len] = '\0';
+ event->len = len;
+ event->done = EINA_FALSE;
+ ret = ECORE_CALLBACK_RENEW;
+ }
+
+ ecore_event_add(ECORE_WL_EVENT_SELECTION_DATA_READY, event,
+ _ecore_wl_dnd_cb_selection_data_ready_free, NULL);
+ return ret;
+}
+
+
+static Eina_Bool
+_ecore_wl_dnd_idler_cb(void *data)
+{
+ struct _dnd_read_ctx *ctx;
+ struct _dnd_task *task;
+ int count, i;
+
+ ctx = data;
+ count = epoll_wait(ctx->epoll_fd, ctx->ep, 1, 0);
+ for (i = 0; i < count; i++)
+ {
+ task = ctx->ep->data.ptr;
+ if (task->cb(task->data, NULL) == ECORE_CALLBACK_CANCEL)
+ {
+ free(ctx->ep);
+ free(task);
+ free(ctx);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type)
+{
+ int epoll_fd;
+ struct epoll_event *ep = NULL;
+ struct _dnd_task *task = NULL;
+ struct _dnd_read_ctx *read_ctx = NULL;
+ int p[2];
+
+ if (pipe2(p, O_CLOEXEC) == -1)
+ return;
+
+ wl_data_offer_receive(source->offer, type, p[1]);
+ close(p[1]);
+
+ /* Due to http://trac.enlightenment.org/e/ticket/1208,
+ * use epoll and idle handler instead of ecore_main_fd_handler_add() */
+
+ ep = calloc(1, sizeof(struct epoll_event));
+ if (!ep) goto err;
+
+ task = calloc(1, sizeof(struct _dnd_task));
+ if (!task) goto err;
+
+ read_ctx = calloc(1, sizeof(struct _dnd_read_ctx));
+ if (!read_ctx) goto err;
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) goto err;
+
+ task->data = source;
+ task->cb = _ecore_wl_dnd_read_data;
+ ep->events = EPOLLIN;
+ ep->data.ptr = task;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, p[0], ep) < 0) goto err;
+
+ read_ctx->epoll_fd = epoll_fd;
+ read_ctx->ep = ep;
+
+ if (!ecore_idler_add(_ecore_wl_dnd_idler_cb, read_ctx)) goto err;
+
+ source->refcount++;
+ source->fd = p[0];
+ return;
+
+err:
+ if (ep) free(ep);
+ if (task) free(task);
+ if (read_ctx) free(read_ctx);
+ close(p[0]);
+ return;
+}
diff --git a/src/lib/ecore_wayland/ecore_wl_input.c b/src/lib/ecore_wayland/ecore_wl_input.c
new file mode 100644
index 0000000000..b8485fb625
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl_input.c
@@ -0,0 +1,1208 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/**
+ * NB: Events that receive a 'serial' instead of timestamp
+ *
+ * input_device_attach (for pointer image)
+ * input_device_button_event (button press/release)
+ * input_device_key_press
+ * input_device_pointer_enter
+ * input_device_pointer_leave
+ * input_device_keyboard_enter
+ * input_device_keyboard_leave
+ * input_device_touch_down
+ * input_device_touch_up
+ *
+ **/
+
+#include "ecore_wl_private.h"
+#include <sys/mman.h>
+#include <sys/timerfd.h>
+
+/* FIXME: This gives BTN_LEFT/RIGHT/MIDDLE for linux systems ...
+ * What about other OSs ?? */
+#ifdef __linux__
+# include <linux/input.h>
+#else
+# define BTN_LEFT 0x110
+# define BTN_RIGHT 0x111
+# define BTN_MIDDLE 0x112
+# define BTN_SIDE 0x113
+# define BTN_EXTRA 0x114
+# define BTN_FORWARD 0x115
+# define BTN_BACK 0x116
+#endif
+
+Ecore_Wl_Dnd *glb_dnd = NULL;
+
+/* local function prototypes */
+static void _ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps);
+
+static void _ecore_wl_input_cb_pointer_enter(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy);
+static void _ecore_wl_input_cb_pointer_leave(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, struct wl_surface *surface);
+static void _ecore_wl_input_cb_pointer_motion(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int timestamp, wl_fixed_t sx, wl_fixed_t sy);
+static void _ecore_wl_input_cb_pointer_button(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, unsigned int timestamp, unsigned int button, unsigned int state);
+static void _ecore_wl_input_cb_pointer_axis(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int timestamp, unsigned int axis, wl_fixed_t value);
+static void _ecore_wl_input_cb_pointer_frame(void *data, struct wl_callback *callback, unsigned int timestamp EINA_UNUSED);
+static void _ecore_wl_input_cb_keyboard_keymap(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int format, int fd, unsigned int size);
+static void _ecore_wl_input_cb_keyboard_enter(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, struct wl_surface *surface, struct wl_array *keys EINA_UNUSED);
+static void _ecore_wl_input_cb_keyboard_leave(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, struct wl_surface *surface);
+static void _ecore_wl_input_cb_keyboard_key(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, unsigned int timestamp, unsigned int key, unsigned int state);
+static void _ecore_wl_input_cb_keyboard_modifiers(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial EINA_UNUSED, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group);
+static Eina_Bool _ecore_wl_input_cb_keyboard_repeat(void *data, Ecore_Fd_Handler *handler EINA_UNUSED);
+static void _ecore_wl_input_cb_touch_down(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int serial, unsigned int timestamp, struct wl_surface *surface EINA_UNUSED, int id EINA_UNUSED, wl_fixed_t x, wl_fixed_t y);
+static void _ecore_wl_input_cb_touch_up(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int serial, unsigned int timestamp, int id EINA_UNUSED);
+static void _ecore_wl_input_cb_touch_motion(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int timestamp, int id EINA_UNUSED, wl_fixed_t x, wl_fixed_t y);
+static void _ecore_wl_input_cb_touch_frame(void *data EINA_UNUSED, struct wl_touch *touch EINA_UNUSED);
+static void _ecore_wl_input_cb_touch_cancel(void *data EINA_UNUSED, struct wl_touch *touch EINA_UNUSED);
+static void _ecore_wl_input_cb_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer);
+static void _ecore_wl_input_cb_data_enter(void *data, struct wl_data_device *data_device, unsigned int timestamp, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer);
+static void _ecore_wl_input_cb_data_leave(void *data, struct wl_data_device *data_device);
+static void _ecore_wl_input_cb_data_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, wl_fixed_t x, wl_fixed_t y);
+static void _ecore_wl_input_cb_data_drop(void *data, struct wl_data_device *data_device);
+static void _ecore_wl_input_cb_data_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer);
+
+static void _ecore_wl_input_mouse_move_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_mouse_in_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_mouse_out_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_focus_in_send(Ecore_Wl_Input *input EINA_UNUSED, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_focus_out_send(Ecore_Wl_Input *input EINA_UNUSED, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_mouse_down_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_mouse_up_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp);
+static void _ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int value, unsigned int timestamp);
+
+/* static int _ecore_wl_input_keysym_to_string(unsigned int symbol, char *buffer, int len); */
+
+/* wayland interfaces */
+static const struct wl_pointer_listener pointer_listener =
+{
+ _ecore_wl_input_cb_pointer_enter,
+ _ecore_wl_input_cb_pointer_leave,
+ _ecore_wl_input_cb_pointer_motion,
+ _ecore_wl_input_cb_pointer_button,
+ _ecore_wl_input_cb_pointer_axis,
+};
+
+static const struct wl_keyboard_listener keyboard_listener =
+{
+ _ecore_wl_input_cb_keyboard_keymap,
+ _ecore_wl_input_cb_keyboard_enter,
+ _ecore_wl_input_cb_keyboard_leave,
+ _ecore_wl_input_cb_keyboard_key,
+ _ecore_wl_input_cb_keyboard_modifiers,
+};
+
+static const struct wl_touch_listener touch_listener =
+{
+ _ecore_wl_input_cb_touch_down,
+ _ecore_wl_input_cb_touch_up,
+ _ecore_wl_input_cb_touch_motion,
+ _ecore_wl_input_cb_touch_frame,
+ _ecore_wl_input_cb_touch_cancel
+};
+
+static const struct wl_seat_listener _ecore_wl_seat_listener =
+{
+ _ecore_wl_input_seat_handle_capabilities,
+};
+
+static const struct wl_data_device_listener _ecore_wl_data_listener =
+{
+ _ecore_wl_input_cb_data_offer,
+ _ecore_wl_input_cb_data_enter,
+ _ecore_wl_input_cb_data_leave,
+ _ecore_wl_input_cb_data_motion,
+ _ecore_wl_input_cb_data_drop,
+ _ecore_wl_input_cb_data_selection
+};
+
+static const struct wl_callback_listener _ecore_wl_pointer_surface_listener =
+{
+ _ecore_wl_input_cb_pointer_frame
+};
+
+/* local variables */
+static int _pointer_x, _pointer_y;
+
+EAPI void
+ecore_wl_input_grab(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int button)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!input) return;
+ input->grab = win;
+ input->grab_button = button;
+}
+
+EAPI void
+ecore_wl_input_ungrab(Ecore_Wl_Input *input)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!input) return;
+ input->grab = NULL;
+ input->grab_button = 0;
+}
+
+EAPI void
+ecore_wl_input_pointer_set(Ecore_Wl_Input *input, struct wl_surface *surface, int hot_x, int hot_y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (input)
+ wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
+ surface, hot_x, hot_y);
+}
+
+EAPI void
+ecore_wl_input_cursor_from_name_set(Ecore_Wl_Input *input, const char *cursor_name)
+{
+ struct wl_cursor_image *cursor_image;
+ struct wl_buffer *buffer;
+ struct wl_cursor *cursor;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!input) return;
+
+ eina_stringshare_replace(&input->cursor_name, cursor_name);
+
+ /* No cursor. Set to default Left Pointer */
+ if (!cursor_name)
+ eina_stringshare_replace(&input->cursor_name, "left_ptr");
+
+ /* try to get this cursor from the theme */
+ if (!(cursor = ecore_wl_cursor_get(input->cursor_name)))
+ {
+ /* if the theme does not have this cursor, default to left pointer */
+ if (!(cursor = ecore_wl_cursor_get("left_ptr")))
+ return;
+ }
+
+ if ((!cursor->images) || (!cursor->images[0]))
+ {
+ ecore_wl_input_pointer_set(input, NULL, 0, 0);
+ return;
+ }
+
+ cursor_image = cursor->images[0];
+ if ((buffer = wl_cursor_image_get_buffer(cursor_image)))
+ {
+ ecore_wl_input_pointer_set(input, input->cursor_surface,
+ cursor_image->hotspot_x,
+ cursor_image->hotspot_y);
+ wl_surface_attach(input->cursor_surface, buffer, 0, 0);
+ wl_surface_damage(input->cursor_surface, 0, 0,
+ cursor_image->width, cursor_image->height);
+ wl_surface_commit(input->cursor_surface);
+
+ if (!input->cursor_frame_cb)
+ _ecore_wl_input_cb_pointer_frame(input, NULL, 0);
+ }
+}
+
+EAPI void
+ecore_wl_input_cursor_default_restore(Ecore_Wl_Input *input)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!input) return;
+
+ /* Restore to default wayland cursor */
+ ecore_wl_input_cursor_from_name_set(input, "left_ptr");
+}
+
+/* local functions */
+void
+_ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = malloc(sizeof(Ecore_Wl_Input)))) return;
+
+ memset(input, 0, sizeof(Ecore_Wl_Input));
+
+ input->display = ewd;
+ input->pointer_focus = NULL;
+ input->keyboard_focus = NULL;
+
+ input->seat =
+ wl_registry_bind(ewd->wl.registry, id, &wl_seat_interface, 1);
+ wl_list_insert(ewd->inputs.prev, &input->link);
+
+ wl_seat_add_listener(input->seat,
+ &_ecore_wl_seat_listener, input);
+ wl_seat_set_user_data(input->seat, input);
+
+ input->data_device =
+ wl_data_device_manager_get_data_device(ewd->wl.data_device_manager,
+ input->seat);
+ wl_data_device_add_listener(input->data_device,
+ &_ecore_wl_data_listener, input);
+ input->cursor_surface =
+ wl_compositor_create_surface(_ecore_wl_disp->wl.compositor);
+
+ input->repeat.timerfd =
+ timerfd_create(CLOCK_MONOTONIC, (TFD_CLOEXEC | TFD_NONBLOCK));
+
+ input->repeat.hdlr =
+ ecore_main_fd_handler_add(input->repeat.timerfd, ECORE_FD_READ,
+ _ecore_wl_input_cb_keyboard_repeat, input,
+ NULL, NULL);
+
+ ewd->input = input;
+
+ /* create Ecore_Wl_Dnd */
+ if (!glb_dnd)
+ if (!(glb_dnd = calloc(1, sizeof(Ecore_Wl_Dnd)))) return;
+ glb_dnd->ewd = ewd;
+ glb_dnd->input = input;
+ input->dnd = glb_dnd;
+ wl_array_init(&glb_dnd->types_offered);
+}
+
+void
+_ecore_wl_input_del(Ecore_Wl_Input *input)
+{
+ if (!input) return;
+
+ if (input->cursor_name) eina_stringshare_del(input->cursor_name);
+ input->cursor_name = NULL;
+
+ if (input->keyboard_focus)
+ {
+ Ecore_Wl_Window *win = NULL;
+
+ if ((win = input->keyboard_focus))
+ win->keyboard_device = NULL;
+
+ input->keyboard_focus = NULL;
+ }
+
+ if (input->drag_source) _ecore_wl_dnd_del(input->drag_source);
+ input->drag_source = NULL;
+
+ if (input->selection_source) _ecore_wl_dnd_del(input->selection_source);
+ input->selection_source = NULL;
+
+ if (input->data_device) wl_data_device_destroy(input->data_device);
+
+ if (input->xkb.state)
+ xkb_state_unref(input->xkb.state);
+ if (input->xkb.keymap)
+ xkb_map_unref(input->xkb.keymap);
+
+ if (input->cursor_surface)
+ wl_surface_destroy(input->cursor_surface);
+
+ wl_list_remove(&input->link);
+ if (input->seat) wl_seat_destroy(input->seat);
+
+ if (input->repeat.hdlr) ecore_main_fd_handler_del(input->repeat.hdlr);
+ input->repeat.hdlr = NULL;
+
+ if (input->repeat.timerfd) close(input->repeat.timerfd);
+ input->repeat.timerfd = 0;
+
+ free(input);
+}
+
+void
+_ecore_wl_input_pointer_xy_get(int *x, int *y)
+{
+ if (x) *x = _pointer_x;
+ if (y) *y = _pointer_y;
+}
+
+static void
+_ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps)
+{
+ Ecore_Wl_Input *input;
+
+ if (!(input = data)) return;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && (!input->pointer))
+ {
+ input->pointer = wl_seat_get_pointer(seat);
+ wl_pointer_set_user_data(input->pointer, input);
+ wl_pointer_add_listener(input->pointer, &pointer_listener, input);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && (input->pointer))
+ {
+ wl_pointer_destroy(input->pointer);
+ input->pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && (!input->keyboard))
+ {
+ input->keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_set_user_data(input->keyboard, input);
+ wl_keyboard_add_listener(input->keyboard, &keyboard_listener, input);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && (input->keyboard))
+ {
+ wl_keyboard_destroy(input->keyboard);
+ input->keyboard = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && (!input->touch))
+ {
+ input->touch = wl_seat_get_touch(seat);
+ wl_touch_set_user_data(input->touch, input);
+ wl_touch_add_listener(input->touch, &touch_listener, input);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && (input->touch))
+ {
+ wl_touch_destroy(input->touch);
+ input->touch = NULL;
+ }
+}
+
+
+static void
+_ecore_wl_input_cb_pointer_motion(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int timestamp, wl_fixed_t sx, wl_fixed_t sy)
+{
+ Ecore_Wl_Input *input;
+
+ /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
+
+ if (!(input = data)) return;
+
+ _pointer_x = input->sx = wl_fixed_to_int(sx);
+ _pointer_y = input->sy = wl_fixed_to_int(sy);
+
+ input->timestamp = timestamp;
+
+ if (input->pointer_focus)
+ _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp);
+}
+
+static void
+_ecore_wl_input_cb_pointer_button(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, unsigned int timestamp, unsigned int button, unsigned int state)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ input->timestamp = timestamp;
+ input->display->serial = serial;
+
+// _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp);
+
+ if (state)
+ {
+ if ((input->pointer_focus) && (!input->grab) && (state))
+ ecore_wl_input_grab(input, input->pointer_focus, button);
+
+ input->button = button;
+ _ecore_wl_input_mouse_down_send(input, input->pointer_focus,
+ timestamp);
+ }
+ else
+ {
+ _ecore_wl_input_mouse_up_send(input, input->pointer_focus,
+ timestamp);
+ input->button = 0;
+
+ if ((input->grab) && (input->grab_button == button) && (!state))
+ ecore_wl_input_ungrab(input);
+ }
+
+// _ecore_wl_input_mouse_move_send(input, timestamp);
+}
+
+static void
+_ecore_wl_input_cb_pointer_axis(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int timestamp, unsigned int axis, wl_fixed_t value)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+ _ecore_wl_input_mouse_wheel_send(input, axis, wl_fixed_to_int(value),
+ timestamp);
+}
+
+static void
+_ecore_wl_input_cb_pointer_frame(void *data, struct wl_callback *callback, unsigned int timestamp EINA_UNUSED)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ if (callback)
+ {
+ if (callback != input->cursor_frame_cb) return;
+ wl_callback_destroy(callback);
+ input->cursor_frame_cb = NULL;
+ }
+
+ if (!input->cursor_name)
+ {
+ ecore_wl_input_pointer_set(input, NULL, 0, 0);
+ return;
+ }
+
+ if (!input->cursor_frame_cb)
+ {
+ input->cursor_frame_cb = wl_surface_frame(input->cursor_surface);
+ wl_callback_add_listener(input->cursor_frame_cb,
+ &_ecore_wl_pointer_surface_listener, input);
+ }
+}
+
+static void
+_ecore_wl_input_cb_keyboard_keymap(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int format, int fd, unsigned int size)
+{
+ Ecore_Wl_Input *input;
+ char *map = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data))
+ {
+ close(fd);
+ return;
+ }
+
+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
+ {
+ close(fd);
+ return;
+ }
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED)
+ {
+ close(fd);
+ return;
+ }
+
+ input->xkb.keymap =
+ xkb_map_new_from_string(input->display->xkb.context, map,
+ XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+
+ munmap(map, size);
+ close(fd);
+
+ if (!(input->xkb.keymap)) return;
+ if (!(input->xkb.state = xkb_state_new(input->xkb.keymap)))
+ {
+ xkb_map_unref(input->xkb.keymap);
+ input->xkb.keymap = NULL;
+ return;
+ }
+
+ input->xkb.control_mask =
+ 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
+ input->xkb.alt_mask =
+ 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1");
+ input->xkb.shift_mask =
+ 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift");
+}
+
+static void
+_ecore_wl_input_cb_keyboard_key(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, unsigned int timestamp, unsigned int keycode, unsigned int state)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win;
+ unsigned int code, num;
+ const xkb_keysym_t *syms;
+ xkb_keysym_t sym = XKB_KEY_NoSymbol;
+ xkb_mod_mask_t mask;
+ char string[32], key[32], keyname[32];// compose[32];
+ Ecore_Event_Key *e;
+ struct itimerspec ts;
+ int len = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+ input->display->serial = serial;
+
+ /* xkb rules reflect X broken keycodes, so offset by 8 */
+ code = keycode + 8;
+
+ win = input->keyboard_focus;
+ if ((!win) || (win->keyboard_device != input) || (!input->xkb.state))
+ return;
+
+ mask = xkb_state_serialize_mods(input->xkb.state,
+ XKB_STATE_DEPRESSED | XKB_STATE_LATCHED);
+
+ input->modifiers = 0;
+
+ /* The Ecore_Event_Modifiers don't quite match the X mask bits */
+ if (mask & input->xkb.control_mask)
+ input->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (mask & input->xkb.alt_mask)
+ input->modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ if (mask & input->xkb.shift_mask)
+ input->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+
+ num = xkb_key_get_syms(input->xkb.state, code, &syms);
+ if (num == 1) sym = syms[0];
+
+ memset(key, 0, sizeof(key));
+ xkb_keysym_get_name(sym, key, sizeof(key));
+
+ memset(keyname, 0, sizeof(keyname));
+ xkb_keysym_get_name(sym, keyname, sizeof(keyname));
+ if (keyname[0] == '\0')
+ snprintf(keyname, sizeof(keyname), "Keycode-%i", code);
+
+ memset(string, 0, sizeof(string));
+ if (xkb_keysym_to_utf8(sym, string, 32) <= 0)
+ {
+ /* FIXME: NB: We may need to add more checks here for other
+ * non-printable characters */
+ if ((sym == XKB_KEY_Tab) || (sym == XKB_KEY_ISO_Left_Tab))
+ string[len++] = '\t';
+ }
+
+ /* FIXME: NB: Start hacking on compose key support */
+ /* memset(compose, 0, sizeof(compose)); */
+ /* if (sym == XKB_KEY_Multi_key) */
+ /* { */
+ /* if (xkb_keysym_to_utf8(sym, compose, 32) <= 0) */
+ /* compose[0] = '\0'; */
+ /* } */
+
+ e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
+ ((string[0] != '\0') ? strlen(string) : 0) + 3);
+ if (!e) return;
+
+ e->keyname = (char *)(e + 1);
+ e->key = e->keyname + strlen(keyname) + 1;
+ e->string = strlen(string) ? e->key + strlen(key) + 1 : NULL;
+ e->compose = e->string;
+
+ strcpy((char *)e->keyname, keyname);
+ strcpy((char *)e->key, key);
+ if (strlen(string)) strcpy((char *)e->string, string);
+
+ e->window = win->id;
+ e->event_window = win->id;
+ e->timestamp = timestamp;
+ e->modifiers = input->modifiers;
+
+ if (state)
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL);
+ else
+ ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
+
+ if ((!state) && (keycode == input->repeat.key))
+ {
+ input->repeat.sym = 0;
+ input->repeat.key = 0;
+ input->repeat.time = 0;
+
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+
+ timerfd_settime(input->repeat.timerfd, 0, &ts, NULL);
+ }
+ else if ((state) &&
+ ((!input->repeat.key) ||
+ ((keycode) && (keycode != input->repeat.key))))
+ {
+ input->repeat.sym = sym;
+ input->repeat.key = keycode;
+ input->repeat.time = timestamp;
+
+ /* interval after expires */
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 35 * 1000 * 1000;
+
+ /* initial expiration */
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 500 * 1000 * 1000;
+
+ timerfd_settime(input->repeat.timerfd, 0, &ts, NULL);
+ }
+}
+
+static void
+_ecore_wl_input_cb_keyboard_modifiers(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial EINA_UNUSED, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+ xkb_state_update_mask(input->xkb.state, depressed, latched,
+ locked, 0, 0, group);
+}
+
+static Eina_Bool
+_ecore_wl_input_cb_keyboard_repeat(void *data, Ecore_Fd_Handler *handler EINA_UNUSED)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win = NULL;
+ unsigned long long int xp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return ECORE_CALLBACK_RENEW;
+
+ /* Trap for EAGAIN */
+ if (read(input->repeat.timerfd, &xp, sizeof(xp)) != sizeof(xp))
+ return ECORE_CALLBACK_RENEW;
+
+ if ((win = input->keyboard_focus))
+ _ecore_wl_input_cb_keyboard_key(input, NULL, input->display->serial,
+ input->repeat.time,
+ input->repeat.key, EINA_TRUE);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_wl_input_cb_pointer_enter(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(input = data)) return;
+
+ if (!input->timestamp)
+ {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ }
+
+ input->sx = wl_fixed_to_double(sx);
+ input->sy = wl_fixed_to_double(sy);
+ input->display->serial = serial;
+ input->pointer_enter_serial = serial;
+
+ /* The cursor on the surface is undefined until we set it */
+ ecore_wl_input_cursor_from_name_set(input, "left_ptr");
+
+ if ((win = wl_surface_get_user_data(surface)))
+ {
+ win->pointer_device = input;
+ input->pointer_focus = win;
+
+ _ecore_wl_input_mouse_in_send(input, win, input->timestamp);
+ }
+
+ /* NB: This whole 'if' below is a major HACK due to wayland's stupidness
+ * of not sending a mouse_up (or any notification at all for that matter)
+ * when a move or resize grab is finished */
+ if (input->grab)
+ {
+ /* NB: This COULD mean a move has finished, or it could mean that
+ * a 'drag' is being done to a different surface */
+
+ if ((input->grab == win) && (win->moving))
+ {
+ /* NB: 'Fake' a mouse_up for move finished */
+ win->moving = EINA_FALSE;
+ _ecore_wl_input_mouse_up_send(input, win, input->timestamp);
+
+ input->button = 0;
+
+ if ((input->grab) && (input->grab_button == BTN_LEFT))
+ ecore_wl_input_ungrab(input);
+ }
+ else if ((input->grab == win) && (win->resizing))
+ {
+ /* NB: 'Fake' a mouse_up for resize finished */
+ win->resizing = EINA_FALSE;
+ _ecore_wl_input_mouse_up_send(input, win, input->timestamp);
+
+ input->button = 0;
+
+ if ((input->grab) && (input->grab_button == BTN_LEFT))
+ ecore_wl_input_ungrab(input);
+ }
+ /* FIXME: Test d-n-d and potentially add needed case here */
+ }
+}
+
+static void
+_ecore_wl_input_cb_pointer_leave(void *data, struct wl_pointer *pointer EINA_UNUSED, unsigned int serial, struct wl_surface *surface)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(input = data)) return;
+
+ input->display->serial = serial;
+
+ if (!surface) return;
+ if (!(win = wl_surface_get_user_data(surface))) return;
+
+ win->pointer_device = NULL;
+ input->pointer_focus = NULL;
+
+ /* _ecore_wl_input_mouse_move_send(input, win, input->timestamp); */
+ _ecore_wl_input_mouse_out_send(input, win, input->timestamp);
+
+ if (input->grab)
+ {
+ /* move or resize started */
+
+ /* printf("Pointer Leave WITH a Grab\n"); */
+ }
+}
+
+static void
+_ecore_wl_input_cb_keyboard_enter(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, struct wl_surface *surface, struct wl_array *keys EINA_UNUSED)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(input = data)) return;
+
+ if (!input->timestamp)
+ {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ }
+
+ input->display->serial = serial;
+
+ if (!(win = wl_surface_get_user_data(surface))) return;
+
+ win->keyboard_device = input;
+ input->keyboard_focus = win;
+
+ _ecore_wl_input_focus_in_send(input, win, input->timestamp);
+}
+
+static void
+_ecore_wl_input_cb_keyboard_leave(void *data, struct wl_keyboard *keyboard EINA_UNUSED, unsigned int serial, struct wl_surface *surface)
+{
+ Ecore_Wl_Input *input;
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(input = data)) return;
+
+ if (input->repeat.timerfd)
+ {
+ struct itimerspec ts;
+
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+
+ timerfd_settime(input->repeat.timerfd, 0, &ts, NULL);
+ }
+
+ if (!input->timestamp)
+ {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ }
+
+ input->display->serial = serial;
+
+ if (!surface) return;
+ if (!(win = wl_surface_get_user_data(surface))) return;
+
+ win->keyboard_device = NULL;
+ _ecore_wl_input_focus_out_send(input, win, input->timestamp);
+
+ input->keyboard_focus = NULL;
+}
+
+static void
+_ecore_wl_input_cb_touch_down(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int serial, unsigned int timestamp, struct wl_surface *surface EINA_UNUSED, int id EINA_UNUSED, wl_fixed_t x, wl_fixed_t y)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(input = data)) return;
+
+ /* FIXME: NB: Not sure yet if input->timestamp should be set here.
+ * This needs to be tested with an actual touch device */
+ /* input->timestamp = timestamp; */
+ input->display->serial = serial;
+ input->button = BTN_LEFT;
+ input->sx = wl_fixed_to_int(x);
+ input->sy = wl_fixed_to_int(y);
+ _ecore_wl_input_cb_pointer_enter(data, NULL, serial, surface, x, y);
+ _ecore_wl_input_mouse_down_send(input, input->pointer_focus, timestamp);
+}
+
+static void
+_ecore_wl_input_cb_touch_up(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int serial, unsigned int timestamp, int id EINA_UNUSED)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ /* FIXME: NB: Not sure yet if input->timestamp should be set here.
+ * This needs to be tested with an actual touch device */
+ /* input->timestamp = timestamp; */
+ input->button = BTN_LEFT;
+ input->display->serial = serial;
+ _ecore_wl_input_mouse_up_send(input, input->pointer_focus, timestamp);
+ input->button = 0;
+}
+
+static void
+_ecore_wl_input_cb_touch_motion(void *data, struct wl_touch *touch EINA_UNUSED, unsigned int timestamp, int id EINA_UNUSED, wl_fixed_t x, wl_fixed_t y)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(input = data)) return;
+
+ /* FIXME: NB: Not sure yet if input->timestamp should be set here.
+ * This needs to be tested with an actual touch device */
+ /* input->timestamp = timestamp; */
+ input->sx = wl_fixed_to_int(x);
+ input->sy = wl_fixed_to_int(y);
+
+ _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp);
+}
+
+static void
+_ecore_wl_input_cb_touch_frame(void *data EINA_UNUSED, struct wl_touch *touch EINA_UNUSED)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+static void
+_ecore_wl_input_cb_touch_cancel(void *data EINA_UNUSED, struct wl_touch *touch EINA_UNUSED)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+static void
+_ecore_wl_input_cb_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_dnd_add(data, data_device, offer);
+}
+
+static void
+_ecore_wl_input_cb_data_enter(void *data, struct wl_data_device *data_device, unsigned int timestamp, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+
+ _ecore_wl_dnd_enter(data, data_device, timestamp, surface, x, y, offer);
+}
+
+static void
+_ecore_wl_input_cb_data_leave(void *data, struct wl_data_device *data_device)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_dnd_leave(data, data_device);
+}
+
+static void
+_ecore_wl_input_cb_data_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, wl_fixed_t x, wl_fixed_t y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_dnd_motion(data, data_device, timestamp, x, y);
+}
+
+static void
+_ecore_wl_input_cb_data_drop(void *data, struct wl_data_device *data_device)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_dnd_drop(data, data_device);
+}
+
+static void
+_ecore_wl_input_cb_data_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_wl_dnd_selection(data, data_device, offer);
+}
+
+static void
+_ecore_wl_input_mouse_move_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Event_Mouse_Move *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Move)))) return;
+
+ ev->timestamp = timestamp;
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+ ev->modifiers = input->modifiers;
+ ev->multi.device = 0;
+ ev->multi.radius = 1;
+ ev->multi.radius_x = 1;
+ ev->multi.radius_y = 1;
+ ev->multi.pressure = 1.0;
+ ev->multi.angle = 0.0;
+ ev->multi.x = input->sx;
+ ev->multi.y = input->sy;
+
+ if (win)
+ {
+ ev->window = win->id;
+ ev->event_window = win->id;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_mouse_in_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Wl_Event_Mouse_In *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Mouse_In)))) return;
+
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+ ev->modifiers = input->modifiers;
+ ev->timestamp = timestamp;
+
+ if (win)
+ {
+ ev->window = win->id;
+ ev->event_window = win->id;
+ }
+
+ ecore_event_add(ECORE_WL_EVENT_MOUSE_IN, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_mouse_out_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Wl_Event_Mouse_Out *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Mouse_Out)))) return;
+
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+ ev->modifiers = input->modifiers;
+ ev->timestamp = timestamp;
+
+ if (win)
+ {
+ ev->window = win->id;
+ ev->event_window = win->id;
+ }
+
+ ecore_event_add(ECORE_WL_EVENT_MOUSE_OUT, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_focus_in_send(Ecore_Wl_Input *input EINA_UNUSED, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Wl_Event_Focus_In *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Focus_In)))) return;
+ ev->timestamp = timestamp;
+ if (win) ev->win = win->id;
+ ecore_event_add(ECORE_WL_EVENT_FOCUS_IN, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_focus_out_send(Ecore_Wl_Input *input EINA_UNUSED, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Wl_Event_Focus_Out *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Focus_Out)))) return;
+ ev->timestamp = timestamp;
+ if (win) ev->win = win->id;
+ ecore_event_add(ECORE_WL_EVENT_FOCUS_OUT, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_mouse_down_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Event_Mouse_Button *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Button)))) return;
+
+ if (input->button == BTN_LEFT)
+ ev->buttons = 1;
+ else if (input->button == BTN_MIDDLE)
+ ev->buttons = 2;
+ else if (input->button == BTN_RIGHT)
+ ev->buttons = 3;
+ else
+ ev->buttons = input->button;
+
+ ev->timestamp = timestamp;
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+ ev->modifiers = input->modifiers;
+
+ /* FIXME: Need to get these from wayland somehow */
+ ev->double_click = 0;
+ ev->triple_click = 0;
+
+ ev->multi.device = 0;
+ ev->multi.radius = 1;
+ ev->multi.radius_x = 1;
+ ev->multi.radius_y = 1;
+ ev->multi.pressure = 1.0;
+ ev->multi.angle = 0.0;
+ ev->multi.x = input->sx;
+ ev->multi.y = input->sy;
+
+ if (win)
+ {
+ ev->window = win->id;
+ ev->event_window = win->id;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_mouse_up_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp)
+{
+ Ecore_Event_Mouse_Button *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Button)))) return;
+
+ if (input->button == BTN_LEFT)
+ ev->buttons = 1;
+ else if (input->button == BTN_MIDDLE)
+ ev->buttons = 2;
+ else if (input->button == BTN_RIGHT)
+ ev->buttons = 3;
+ else
+ ev->buttons = input->button;
+
+ ev->timestamp = timestamp;
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+ ev->modifiers = input->modifiers;
+
+ /* FIXME: Need to get these from wayland somehow */
+ ev->double_click = 0;
+ ev->triple_click = 0;
+
+ ev->multi.device = 0;
+ ev->multi.radius = 1;
+ ev->multi.radius_x = 1;
+ ev->multi.radius_y = 1;
+ ev->multi.pressure = 1.0;
+ ev->multi.angle = 0.0;
+ ev->multi.x = input->sx;
+ ev->multi.y = input->sy;
+
+ if (win)
+ {
+ ev->window = win->id;
+ ev->event_window = win->id;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+}
+
+static void
+_ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int value, unsigned int timestamp)
+{
+ Ecore_Event_Mouse_Wheel *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Wheel)))) return;
+
+ ev->timestamp = timestamp;
+ ev->modifiers = input->modifiers;
+ ev->x = input->sx;
+ ev->y = input->sy;
+ /* ev->root.x = input->sx; */
+ /* ev->root.y = input->sy; */
+
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+ {
+ ev->direction = 0;
+ ev->z = value;
+ }
+ else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
+ {
+ ev->direction = 1;
+ ev->z = value;
+ }
+
+ if (input->grab)
+ {
+ ev->window = input->grab->id;
+ ev->event_window = input->grab->id;
+ }
+ else if (input->pointer_focus)
+ {
+ ev->window = input->pointer_focus->id;
+ ev->event_window = input->pointer_focus->id;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
+}
+
+void
+_ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source)
+{
+ wl_data_device_set_selection(input->data_device, source, input->display->serial);
+}
+
diff --git a/src/lib/ecore_wayland/ecore_wl_output.c b/src/lib/ecore_wayland/ecore_wl_output.c
new file mode 100644
index 0000000000..5498895007
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl_output.c
@@ -0,0 +1,87 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecore_wl_private.h"
+
+/* local function prototypes */
+static void _ecore_wl_output_cb_geometry(void *data, struct wl_output *wl_output EINA_UNUSED, int x, int y, int w, int h, int subpixel EINA_UNUSED, const char *make EINA_UNUSED, const char *model EINA_UNUSED, int transform EINA_UNUSED);
+static void _ecore_wl_output_cb_mode(void *data, struct wl_output *wl_output EINA_UNUSED, unsigned int flags, int w, int h, int refresh EINA_UNUSED);
+
+/* wayland listeners */
+static const struct wl_output_listener _ecore_wl_output_listener =
+{
+ _ecore_wl_output_cb_geometry,
+ _ecore_wl_output_cb_mode
+};
+
+/* @since 1.2 */
+EAPI struct wl_list
+ecore_wl_outputs_get(void)
+{
+ return _ecore_wl_disp->outputs;
+}
+
+void
+_ecore_wl_output_add(Ecore_Wl_Display *ewd, unsigned int id)
+{
+ Ecore_Wl_Output *output;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(output = malloc(sizeof(Ecore_Wl_Output)))) return;
+
+ memset(output, 0, sizeof(Ecore_Wl_Output));
+
+ output->display = ewd;
+
+ output->output =
+ wl_registry_bind(ewd->wl.registry, id, &wl_output_interface, 1);
+
+ wl_list_insert(ewd->outputs.prev, &output->link);
+ wl_output_add_listener(output->output, &_ecore_wl_output_listener, output);
+}
+
+void
+_ecore_wl_output_del(Ecore_Wl_Output *output)
+{
+ if (!output) return;
+ if (output->destroy) (*output->destroy)(output, output->data);
+ if (output->output) wl_output_destroy(output->output);
+ wl_list_remove(&output->link);
+ free(output);
+}
+
+/* local functions */
+static void
+_ecore_wl_output_cb_geometry(void *data, struct wl_output *wl_output EINA_UNUSED, int x, int y, int w, int h, int subpixel EINA_UNUSED, const char *make EINA_UNUSED, const char *model EINA_UNUSED, int transform EINA_UNUSED)
+{
+ Ecore_Wl_Output *output;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ output = data;
+ output->allocation.x = x;
+ output->allocation.y = y;
+ output->mw = w;
+ output->mh = h;
+}
+
+static void
+_ecore_wl_output_cb_mode(void *data, struct wl_output *wl_output EINA_UNUSED, unsigned int flags, int w, int h, int refresh EINA_UNUSED)
+{
+ Ecore_Wl_Output *output;
+ Ecore_Wl_Display *ewd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ output = data;
+ ewd = output->display;
+ if (flags & WL_OUTPUT_MODE_CURRENT)
+ {
+ output->allocation.w = w;
+ output->allocation.h = h;
+ _ecore_wl_disp->output = output;
+ if (ewd->output_configure) (*ewd->output_configure)(output, ewd->data);
+ }
+}
diff --git a/src/lib/ecore_wayland/ecore_wl_private.h b/src/lib/ecore_wayland/ecore_wl_private.h
new file mode 100644
index 0000000000..ecd7a110b3
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl_private.h
@@ -0,0 +1,103 @@
+#ifndef _ECORE_WAYLAND_PRIVATE_H
+# define _ECORE_WAYLAND_PRIVATE_H
+
+# include <limits.h>
+# include <unistd.h>
+
+# include "Ecore.h"
+# include "Ecore_Input.h"
+# include "Ecore_Wayland.h"
+
+//# define LOGFNS 1
+
+# ifdef LOGFNS
+# include <stdio.h>
+# define LOGFN(fl, ln, fn) printf("-ECORE-WL: %25s: %5i - %s\n", fl, ln, fn);
+# else
+# define LOGFN(fl, ln, fn)
+# endif
+
+extern int _ecore_wl_log_dom;
+extern Ecore_Wl_Display *_ecore_wl_disp;
+
+# ifdef ECORE_WL_DEFAULT_LOG_COLOR
+# undef ECORE_WL_DEFAULT_LOG_COLOR
+# endif
+# define ECORE_WL_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+# ifdef ERR
+# undef ERR
+# endif
+# define ERR(...) EINA_LOG_DOM_ERR(_ecore_wl_log_dom, __VA_ARGS__)
+
+# ifdef DBG
+# undef DBG
+# endif
+# define DBG(...) EINA_LOG_DOM_DBG(_ecore_wl_log_dom, __VA_ARGS__)
+
+# ifdef INF
+# undef INF
+# endif
+# define INF(...) EINA_LOG_DOM_INFO(_ecore_wl_log_dom, __VA_ARGS__)
+
+# ifdef WRN
+# undef WRN
+# endif
+# define WRN(...) EINA_LOG_DOM_WARN(_ecore_wl_log_dom, __VA_ARGS__)
+
+# ifdef CRIT
+# undef CRIT
+# endif
+# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_wl_log_dom, __VA_ARGS__)
+
+struct _Ecore_Wl_Dnd
+{
+ Ecore_Wl_Display *ewd;
+ Ecore_Wl_Input *input;
+
+ /* As provider */
+ struct wl_data_source *data_source;
+ struct wl_array types_offered;
+
+ /* TODO: dnd specific fields */
+};
+
+struct _Ecore_Wl_Dnd_Source
+{
+ struct wl_data_offer *offer;
+ Ecore_Wl_Input *input;
+ struct wl_array types;
+ int refcount;
+ int fd;
+ int x, y;
+
+ /* TODO: task & data_func */
+ void *data;
+};
+
+struct _Ecore_Wl_Dnd_Target
+{
+ Ecore_Wl_Dnd_Source *source;
+};
+
+void _ecore_wl_window_init(void);
+void _ecore_wl_window_shutdown(void);
+
+void _ecore_wl_output_add(Ecore_Wl_Display *ewd, unsigned int id);
+void _ecore_wl_output_del(Ecore_Wl_Output *output);
+
+void _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id);
+void _ecore_wl_input_del(Ecore_Wl_Input *input);
+void _ecore_wl_input_pointer_xy_get(int *x, int *y);
+void _ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source);
+
+void _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device, struct wl_data_offer *offer);
+void _ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device, unsigned int timestamp, struct wl_surface *surface, int x, int y, struct wl_data_offer *offer);
+void _ecore_wl_dnd_leave(void *data, struct wl_data_device *data_device);
+void _ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, int x, int y);
+void _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device);
+void _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer);
+void _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source);
+
+struct wl_data_source *_ecore_wl_create_data_source(Ecore_Wl_Display *ewd);
+#endif
diff --git a/src/lib/ecore_wayland/ecore_wl_window.c b/src/lib/ecore_wayland/ecore_wl_window.c
new file mode 100644
index 0000000000..3d221e9f2a
--- /dev/null
+++ b/src/lib/ecore_wayland/ecore_wl_window.c
@@ -0,0 +1,707 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecore_wl_private.h"
+
+/* local function prototypes */
+static void _ecore_wl_window_cb_ping(void *data EINA_UNUSED, struct wl_shell_surface *shell_surface, unsigned int serial);
+static void _ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface EINA_UNUSED, unsigned int edges, int w, int h);
+static void _ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface EINA_UNUSED);
+static void _ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output EINA_UNUSED);
+static void _ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output EINA_UNUSED);
+static void _ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h);
+static char *_ecore_wl_window_id_str_get(unsigned int win_id);
+
+/* local variables */
+static Eina_Hash *_windows = NULL;
+
+/* wayland listeners */
+static const struct wl_surface_listener _ecore_wl_surface_listener =
+{
+ _ecore_wl_window_cb_surface_enter,
+ _ecore_wl_window_cb_surface_leave
+};
+
+static const struct wl_shell_surface_listener _ecore_wl_shell_surface_listener =
+{
+ _ecore_wl_window_cb_ping,
+ _ecore_wl_window_cb_configure,
+ _ecore_wl_window_cb_popup_done
+};
+
+/* internal functions */
+void
+_ecore_wl_window_init(void)
+{
+ if (!_windows)
+ _windows = eina_hash_string_superfast_new(NULL);
+}
+
+void
+_ecore_wl_window_shutdown(void)
+{
+ eina_hash_free(_windows);
+ _windows = NULL;
+}
+
+/**
+ * @defgroup Ecore_Wl_Window_Group Wayland Library Init and Shutdown Functions
+ *
+ * Functions that can be used to create a Wayland window.
+ */
+
+/**
+ * Creates a new window
+ *
+ * @param parent The parent window to use. If @p parent is @c 0, the root window
+ * of the default display is used.
+ * @param x X Position
+ * @param y Y position
+ * @param w Width
+ * @param h Height
+ * @param buffer_type The type of the buffer to be used to create a new Ecore_Wl_Window.
+ *
+ * @return The new window
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI Ecore_Wl_Window *
+ecore_wl_window_new(Ecore_Wl_Window *parent, int x, int y, int w, int h, int buffer_type)
+{
+ Ecore_Wl_Window *win;
+ static int _win_id = 1;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(win = malloc(sizeof(Ecore_Wl_Window))))
+ {
+ ERR("Failed to allocate an Ecore Wayland Window");
+ return NULL;
+ }
+
+ memset(win, 0, sizeof(Ecore_Wl_Window));
+
+ win->display = _ecore_wl_disp;
+ win->parent = parent;
+ win->allocation.x = x;
+ win->allocation.y = y;
+ win->allocation.w = w;
+ win->allocation.h = h;
+ win->saved_allocation = win->allocation;
+ win->transparent = EINA_FALSE;
+ /* win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; */
+ win->type = ECORE_WL_WINDOW_TYPE_NONE;
+ win->buffer_type = buffer_type;
+ win->id = _win_id++;
+
+ eina_hash_add(_windows, _ecore_wl_window_id_str_get(win->id), win);
+ return win;
+}
+
+/**
+ * Deletes the given window
+ *
+ * @param win The given window
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_free(Ecore_Wl_Window *win)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ eina_hash_del(_windows, _ecore_wl_window_id_str_get(win->id), win);
+
+ wl_list_for_each(input, &_ecore_wl_disp->inputs, link)
+ {
+ if ((input->pointer_focus) && (input->pointer_focus == win))
+ input->pointer_focus = NULL;
+ if ((input->keyboard_focus) && (input->keyboard_focus == win))
+ input->keyboard_focus = NULL;
+ }
+
+ if (win->region.input) wl_region_destroy(win->region.input);
+ win->region.input = NULL;
+ if (win->region.opaque) wl_region_destroy(win->region.opaque);
+ win->region.opaque = NULL;
+ if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface);
+ win->shell_surface = NULL;
+
+ if (win->surface) wl_surface_destroy(win->surface);
+ win->surface = NULL;
+
+ /* HMMM, why was this disabled ? */
+ free(win);
+}
+
+/**
+ * Signals for Wayland to initiate a window move.
+ *
+ * The position requested (@p x, @p y) is not honored by Wayland because
+ * Wayland does not allow specific window placement to be set.
+ *
+ * @param win The window to move.
+ * @param x X Position
+ * @param y Y Position
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_move(Ecore_Wl_Window *win, int x, int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ win->allocation.x = x;
+ win->allocation.y = y;
+
+ if (win->shell_surface)
+ {
+ Ecore_Wl_Input *input;
+
+ if (!(input = win->keyboard_device))
+ {
+ if (win->parent)
+ {
+ if (!(input = win->parent->keyboard_device))
+ input = win->parent->pointer_device;
+ }
+ }
+
+ if ((!input) || (!input->seat)) return;
+
+ wl_shell_surface_move(win->shell_surface, input->seat,
+ input->display->serial);
+ }
+}
+
+/**
+ * Signals for Wayland to initiate a window resize.
+ *
+ * The size requested (@p w, @p h) is not honored by Wayland because
+ * Wayland does not allow specific window sizes to be set.
+ *
+ * @param win The window to resize.
+ * @param w Width
+ * @param h Height
+ * @param location The edge of the window from where the resize should start.
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_resize(Ecore_Wl_Window *win, int w, int h, int location)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN)
+ {
+ win->allocation.w = w;
+ win->allocation.h = h;
+
+ win->region.input =
+ wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
+ wl_region_add(win->region.input, win->allocation.x, win->allocation.y,
+ win->allocation.w, win->allocation.h);
+ }
+
+ if (!win->transparent)
+ {
+ win->region.opaque =
+ wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
+ wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y,
+ win->allocation.w, win->allocation.h);
+ }
+
+ if (win->shell_surface)
+ {
+ Ecore_Wl_Input *input;
+
+ if (!(input = win->keyboard_device))
+ {
+ if (win->parent)
+ {
+ if (!(input = win->parent->keyboard_device))
+ input = win->parent->pointer_device;
+ }
+ }
+
+ if ((!input) || (!input->seat)) return;
+
+ wl_shell_surface_resize(win->shell_surface, input->seat,
+ input->display->serial, location);
+ }
+}
+
+EAPI void
+ecore_wl_window_damage(Ecore_Wl_Window *win, int x, int y, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ if (win->surface)
+ {
+ wl_surface_damage(win->surface, x, y, w, h);
+ wl_surface_commit(win->surface);
+ }
+}
+
+EAPI void
+ecore_wl_window_buffer_attach(Ecore_Wl_Window *win, struct wl_buffer *buffer, int x, int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ switch (win->buffer_type)
+ {
+ case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW:
+ win->server_allocation = win->allocation;
+ break;
+ case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_IMAGE:
+ case ECORE_WL_WINDOW_BUFFER_TYPE_SHM:
+ if (win->surface)
+ {
+ if (win->edges & 4) // resizing from the left
+ x = win->server_allocation.w - win->allocation.w;
+ else
+ x = 0;
+
+ if (win->edges & 1) // resizing from the top
+ y = win->server_allocation.h - win->allocation.h;
+ else
+ y = 0;
+
+ win->edges = 0;
+
+ /* if (buffer) */
+ wl_surface_attach(win->surface, buffer, x, y);
+ wl_surface_damage(win->surface, 0, 0,
+ win->allocation.w, win->allocation.h);
+ wl_surface_commit(win->surface);
+
+ win->server_allocation = win->allocation;
+ }
+ break;
+ default:
+ return;
+ }
+
+ if (win->region.input)
+ {
+ wl_surface_set_input_region(win->surface, win->region.input);
+ wl_region_destroy(win->region.input);
+ win->region.input = NULL;
+ }
+
+ if (win->region.opaque)
+ {
+ wl_surface_set_opaque_region(win->surface, win->region.opaque);
+ wl_region_destroy(win->region.opaque);
+ win->region.opaque = NULL;
+ }
+}
+
+/**
+ * Shows a window
+ *
+ * Synonymous to "mapping" a window in Wayland System terminology.
+ *
+ * @param win The window to show.
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_show(Ecore_Wl_Window *win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ if (win->surface) return;
+
+ win->surface = wl_compositor_create_surface(_ecore_wl_disp->wl.compositor);
+ wl_surface_set_user_data(win->surface, win);
+ /* wl_surface_add_listener(win->surface, &_ecore_wl_surface_listener, win); */
+
+ win->shell_surface =
+ wl_shell_get_shell_surface(_ecore_wl_disp->wl.shell, win->surface);
+ wl_shell_surface_add_listener(win->shell_surface,
+ &_ecore_wl_shell_surface_listener, win);
+
+ switch (win->type)
+ {
+ case ECORE_WL_WINDOW_TYPE_FULLSCREEN:
+ wl_shell_surface_set_fullscreen(win->shell_surface,
+ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+ 0, NULL);
+ break;
+ case ECORE_WL_WINDOW_TYPE_MAXIMIZED:
+ wl_shell_surface_set_maximized(win->shell_surface, NULL);
+ break;
+ case ECORE_WL_WINDOW_TYPE_TRANSIENT:
+ wl_shell_surface_set_transient(win->shell_surface,
+ win->parent->surface,
+ win->allocation.x, win->allocation.y, 0);
+ break;
+ case ECORE_WL_WINDOW_TYPE_MENU:
+ wl_shell_surface_set_popup(win->shell_surface,
+ _ecore_wl_disp->input->seat,
+ _ecore_wl_disp->serial,
+ win->parent->surface,
+ win->allocation.x, win->allocation.y, 0);
+ break;
+ case ECORE_WL_WINDOW_TYPE_NONE:
+ win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
+ /* fallthrough */
+ case ECORE_WL_WINDOW_TYPE_TOPLEVEL:
+ wl_shell_surface_set_toplevel(win->shell_surface);
+ break;
+ default:
+ break;
+ }
+
+ /* if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN) */
+ /* { */
+ /* win->region.input = */
+ /* wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */
+ /* wl_region_add(win->region.input, win->allocation.x, win->allocation.y, */
+ /* win->allocation.w, win->allocation.h); */
+ /* } */
+
+ /* if (!win->transparent) */
+ /* { */
+ /* win->region.opaque = */
+ /* wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */
+ /* wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, */
+ /* win->allocation.w, win->allocation.h); */
+ /* } */
+}
+
+/**
+ * Hides a window
+ *
+ * Synonymous to "unmapping" a window in Wayland System terminology.
+ *
+ * @param win The window to hide.
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_hide(Ecore_Wl_Window *win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface);
+ win->shell_surface = NULL;
+ if (win->surface) wl_surface_destroy(win->surface);
+ win->surface = NULL;
+}
+
+/**
+ * Raises a window
+ *
+ * @param win The window to raise.
+ *
+ * @ingroup Ecore_Wl_Window_Group
+ * @since 1.2
+ */
+EAPI void
+ecore_wl_window_raise(Ecore_Wl_Window *win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ if (win->shell_surface)
+ wl_shell_surface_set_toplevel(win->shell_surface);
+}
+
+EAPI void
+ecore_wl_window_maximized_set(Ecore_Wl_Window *win, Eina_Bool maximized)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ if ((win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED) == maximized) return;
+ if (win->type == ECORE_WL_WINDOW_TYPE_TOPLEVEL)
+ {
+ win->saved_allocation = win->allocation;
+ if (win->shell_surface)
+ wl_shell_surface_set_maximized(win->shell_surface, NULL);
+ win->type = ECORE_WL_WINDOW_TYPE_MAXIMIZED;
+ }
+ else if (win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED)
+ {
+ if (win->shell_surface)
+ wl_shell_surface_set_toplevel(win->shell_surface);
+ win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
+ _ecore_wl_window_configure_send(win, win->saved_allocation.w,
+ win->saved_allocation.h);
+ }
+}
+
+EAPI void
+ecore_wl_window_fullscreen_set(Ecore_Wl_Window *win, Eina_Bool fullscreen)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ if ((win->type == ECORE_WL_WINDOW_TYPE_FULLSCREEN) == fullscreen) return;
+ if (fullscreen)
+ {
+ win->type = ECORE_WL_WINDOW_TYPE_FULLSCREEN;
+ win->saved_allocation = win->allocation;
+ if (win->shell_surface)
+ wl_shell_surface_set_fullscreen(win->shell_surface,
+ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+ 0, NULL);
+ }
+ else
+ {
+ if (win->shell_surface)
+ wl_shell_surface_set_toplevel(win->shell_surface);
+ win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
+ _ecore_wl_window_configure_send(win, win->saved_allocation.w,
+ win->saved_allocation.h);
+ }
+}
+
+EAPI void
+ecore_wl_window_transparent_set(Ecore_Wl_Window *win, Eina_Bool transparent)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ win->transparent = transparent;
+ if (win->region.opaque) wl_region_destroy(win->region.opaque);
+ win->region.opaque = NULL;
+ if (!win->transparent)
+ {
+ win->region.opaque =
+ wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
+ wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y,
+ win->allocation.w, win->allocation.h);
+ }
+}
+
+EAPI void
+ecore_wl_window_update_size(Ecore_Wl_Window *win, int w, int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ win->allocation.w = w;
+ win->allocation.h = h;
+}
+
+EAPI void
+ecore_wl_window_update_location(Ecore_Wl_Window *win, int x, int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ win->allocation.x = x;
+ win->allocation.y = y;
+}
+
+EAPI struct wl_surface *
+ecore_wl_window_surface_get(Ecore_Wl_Window *win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return NULL;
+ return win->surface;
+}
+
+/* @since 1.2 */
+EAPI struct wl_shell_surface *
+ecore_wl_window_shell_surface_get(Ecore_Wl_Window *win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return NULL;
+ return win->shell_surface;
+}
+
+EAPI Ecore_Wl_Window *
+ecore_wl_window_find(unsigned int id)
+{
+ Ecore_Wl_Window *win = NULL;
+
+ win = eina_hash_find(_windows, _ecore_wl_window_id_str_get(id));
+ return win;
+}
+
+EAPI void
+ecore_wl_window_type_set(Ecore_Wl_Window *win, Ecore_Wl_Window_Type type)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ win->type = type;
+}
+
+EAPI void
+ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *surface, int hot_x, int hot_y)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ if ((input = win->pointer_device))
+ ecore_wl_input_pointer_set(input, surface, hot_x, hot_y);
+}
+
+EAPI void
+ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ if ((input = win->pointer_device))
+ ecore_wl_input_cursor_from_name_set(input, cursor_name);
+}
+
+EAPI void
+ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win)
+{
+ Ecore_Wl_Input *input;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+
+ if ((input = win->pointer_device))
+ ecore_wl_input_cursor_default_restore(input);
+}
+
+/* @since 1.2 */
+EAPI void
+ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ win->parent = parent;
+}
+
+/* local functions */
+static void
+_ecore_wl_window_cb_ping(void *data EINA_UNUSED, struct wl_shell_surface *shell_surface, unsigned int serial)
+{
+ if (!shell_surface) return;
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void
+_ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface EINA_UNUSED, unsigned int edges, int w, int h)
+{
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(win = data)) return;
+
+ if ((w <= 0) || (h <= 0)) return;
+
+ if ((win->allocation.w != w) || (win->allocation.h != h))
+ {
+ win->edges = edges;
+ if (win->region.input) wl_region_destroy(win->region.input);
+ win->region.input = NULL;
+ if (win->region.opaque) wl_region_destroy(win->region.opaque);
+ win->region.opaque = NULL;
+
+ _ecore_wl_window_configure_send(win, w, h);
+ }
+}
+
+static void
+_ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface EINA_UNUSED)
+{
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!shell_surface) return;
+ if (!(win = data)) return;
+ ecore_wl_input_ungrab(win->pointer_device);
+}
+
+static void
+_ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output EINA_UNUSED)
+{
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(win = data)) return;
+}
+
+static void
+_ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output EINA_UNUSED)
+{
+ Ecore_Wl_Window *win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!surface) return;
+ if (!(win = data)) return;
+}
+
+static void
+_ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h)
+{
+ Ecore_Wl_Event_Window_Configure *ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Window_Configure)))) return;
+ ev->win = win->id;
+ ev->event_win = win->id;
+ ev->x = win->allocation.x;
+ ev->y = win->allocation.y;
+ ev->w = w;
+ ev->h = h;
+ ecore_event_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, ev, NULL, NULL);
+}
+
+static char *
+_ecore_wl_window_id_str_get(unsigned int win_id)
+{
+ const char *vals = "qWeRtYuIoP5$&<~";
+ static char id[9];
+ unsigned int val;
+
+ val = win_id;
+ id[0] = vals[(val >> 28) & 0xf];
+ id[1] = vals[(val >> 24) & 0xf];
+ id[2] = vals[(val >> 20) & 0xf];
+ id[3] = vals[(val >> 16) & 0xf];
+ id[4] = vals[(val >> 12) & 0xf];
+ id[5] = vals[(val >> 8) & 0xf];
+ id[6] = vals[(val >> 4) & 0xf];
+ id[7] = vals[(val) & 0xf];
+ id[8] = 0;
+
+ return id;
+}
diff --git a/src/lib/ecore_win32/Ecore_Win32.h b/src/lib/ecore_win32/Ecore_Win32.h
new file mode 100644
index 0000000000..ae1bd4ec8c
--- /dev/null
+++ b/src/lib/ecore_win32/Ecore_Win32.h
@@ -0,0 +1,526 @@
+#ifndef __ECORE_WIN32_H__
+#define __ECORE_WIN32_H__
+
+/*
+ * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND
+ * THE API MAY CHANGE.
+ */
+
+#ifndef ECORE_WIN32_WIP_POZEFLKSD
+# ifdef _MSC_VER
+# pragma message ("You are using a work in progress API. This API is not stable")
+# pragma message ("and is subject to change. You use this at your own risk.")
+# else
+# warning "You are using a work in progress API. This API is not stable"
+# warning "and is subject to change. You use this at your own risk."
+# endif
+#endif
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_WIN32_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_WIN32_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_Win32_Group Ecore_Win32 library
+ *
+ * @{
+ */
+
+/**
+ * @typedef Ecore_Win32_Window_State
+ * State of a window.
+ */
+typedef enum
+{
+ ECORE_WIN32_WINDOW_STATE_ICONIFIED, /**< iconified window */
+ ECORE_WIN32_WINDOW_STATE_MODAL, /**< modal dialog box */
+ ECORE_WIN32_WINDOW_STATE_STICKY, /**< sticky window */
+ ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT, /**< maximum vertical sized window */
+ ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ, /**< maximum horizontal sized window */
+ ECORE_WIN32_WINDOW_STATE_MAXIMIZED, /**< maximum sized window */
+ ECORE_WIN32_WINDOW_STATE_SHADED, /**< shaded window */
+ ECORE_WIN32_WINDOW_STATE_HIDDEN, /**< hidden (minimized or iconified) window */
+ ECORE_WIN32_WINDOW_STATE_FULLSCREEN, /**< fullscreen window */
+ ECORE_WIN32_WINDOW_STATE_ABOVE, /**< above window */
+ ECORE_WIN32_WINDOW_STATE_BELOW, /**< below window */
+ ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION, /**< To document */
+ ECORE_WIN32_WINDOW_STATE_UNKNOWN /**< Unknown state */
+} Ecore_Win32_Window_State;
+
+/**
+ * @typedef Ecore_Win32_Window_Type
+ * Type of a window.
+ */
+typedef enum
+{
+ ECORE_WIN32_WINDOW_TYPE_DESKTOP, /**< Desktop feature */
+ ECORE_WIN32_WINDOW_TYPE_DOCK, /**< Dock window (should be on top of other windows) */
+ ECORE_WIN32_WINDOW_TYPE_TOOLBAR, /**< Toolbar window */
+ ECORE_WIN32_WINDOW_TYPE_MENU, /**< Menu window */
+ ECORE_WIN32_WINDOW_TYPE_UTILITY, /**< Small persistent utility window, such as a palette or toolbox */
+ ECORE_WIN32_WINDOW_TYPE_SPLASH, /**< Splash screen window displayed as an application is starting up */
+ ECORE_WIN32_WINDOW_TYPE_DIALOG, /**< Dialog window */
+ ECORE_WIN32_WINDOW_TYPE_NORMAL, /**< Normal top-level window */
+ ECORE_WIN32_WINDOW_TYPE_UNKNOWN /**< Unknown type */
+} Ecore_Win32_Window_Type;
+
+/**
+ * @typedef Ecore_Win32_Cursor_Shape
+ * Shape of a cursor.
+ */
+typedef enum
+{
+ ECORE_WIN32_CURSOR_SHAPE_APP_STARTING, /**< Standard arrow and small hourglass */
+ ECORE_WIN32_CURSOR_SHAPE_ARROW, /**< Standard arrow */
+ ECORE_WIN32_CURSOR_SHAPE_CROSS, /**< Crosshair */
+ ECORE_WIN32_CURSOR_SHAPE_HAND, /**< Hand */
+ ECORE_WIN32_CURSOR_SHAPE_HELP, /**< Arrow and question mark */
+ ECORE_WIN32_CURSOR_SHAPE_I_BEAM, /**< I-beam */
+ ECORE_WIN32_CURSOR_SHAPE_NO, /**< Slashed circle */
+ ECORE_WIN32_CURSOR_SHAPE_SIZE_ALL, /**< Four-pointed arrow pointing north, south, east, and west */
+ ECORE_WIN32_CURSOR_SHAPE_SIZE_NESW, /**< Double-pointed arrow pointing northeast and southwest */
+ ECORE_WIN32_CURSOR_SHAPE_SIZE_NS, /**< Double-pointed arrow pointing north and south */
+ ECORE_WIN32_CURSOR_SHAPE_SIZE_NWSE, /**< Double-pointed arrow pointing northwest and southeast */
+ ECORE_WIN32_CURSOR_SHAPE_SIZE_WE, /**< Double-pointed arrow pointing west and east */
+ ECORE_WIN32_CURSOR_SHAPE_UP_ARROW, /**< Vertical arrow */
+ ECORE_WIN32_CURSOR_SHAPE_WAIT /**< Hourglass */
+} Ecore_Win32_Cursor_Shape;
+
+/**
+ * @typedef Ecore_Win32_DnD_State
+ * State of a DnD operation.
+ */
+typedef enum
+{
+ ECORE_WIN32_DND_EVENT_DRAG_ENTER = 1, /**< Drag enter */
+ ECORE_WIN32_DND_EVENT_DRAG_OVER = 2, /**< Drag over */
+ ECORE_WIN32_DND_EVENT_DRAG_LEAVE = 3, /**< Drag leave */
+ ECORE_WIN32_DND_EVENT_DROP = 4 /**< Drop */
+} Ecore_Win32_DnD_State;
+
+/**
+ * @typedef Ecore_Win32_Window
+ * Abstract type for a window.
+ */
+typedef struct _Ecore_Win32_Window Ecore_Win32_Window;
+
+/**
+ * @typedef Ecore_Win32_Cursor
+ * Abstract type for a cursor.
+ */
+typedef void Ecore_Win32_Cursor;
+
+
+/**
+ * @typedef Ecore_Win32_Event_Mouse_In
+ * Event sent when the mouse enters the window.
+ */
+typedef struct _Ecore_Win32_Event_Mouse_In Ecore_Win32_Event_Mouse_In;
+
+/**
+ * @typedef Ecore_Win32_Event_Mouse_Out
+ * Event sent when the mouse leaves the window.
+ */
+typedef struct _Ecore_Win32_Event_Mouse_Out Ecore_Win32_Event_Mouse_Out;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Focus_In
+ * Event sent when the window gets the focus.
+ */
+typedef struct _Ecore_Win32_Event_Window_Focus_In Ecore_Win32_Event_Window_Focus_In;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Focus_Out
+ * Event sent when the window looses the focus.
+ */
+typedef struct _Ecore_Win32_Event_Window_Focus_Out Ecore_Win32_Event_Window_Focus_Out;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Damage
+ * Event sent when the window is damaged.
+ */
+typedef struct _Ecore_Win32_Event_Window_Damage Ecore_Win32_Event_Window_Damage;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Create
+ * Event sent when the window is created.
+ */
+typedef struct _Ecore_Win32_Event_Window_Create Ecore_Win32_Event_Window_Create;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Destroy
+ * Event sent when the window is destroyed.
+ */
+typedef struct _Ecore_Win32_Event_Window_Destroy Ecore_Win32_Event_Window_Destroy;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Hide
+ * Event sent when the window is hidden.
+ */
+typedef struct _Ecore_Win32_Event_Window_Hide Ecore_Win32_Event_Window_Hide;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Show
+ * Event sent when the window is shown.
+ */
+typedef struct _Ecore_Win32_Event_Window_Show Ecore_Win32_Event_Window_Show;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Configure
+ * Event sent when the window is configured.
+ */
+typedef struct _Ecore_Win32_Event_Window_Configure Ecore_Win32_Event_Window_Configure;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Resize
+ * Event sent when the window is resized.
+ */
+typedef struct _Ecore_Win32_Event_Window_Resize Ecore_Win32_Event_Window_Resize;
+
+/**
+ * @typedef Ecore_Win32_Event_Window_Delete_Request
+ * Event sent when the window is deleted.
+ */
+typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window_Delete_Request;
+
+/**
+ * @struct _Ecore_Win32_Event_Mouse_In
+ * Event sent when the mouse enters the window.
+ */
+struct _Ecore_Win32_Event_Mouse_In
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate where the mouse leaved */
+ int y; /**< The y coordinate where the mouse entered */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Mouse_Out
+ * Event sent when the mouse leaves the window.
+ */
+struct _Ecore_Win32_Event_Mouse_Out
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate where the mouse leaved */
+ int y; /**< The y coordinate where the mouse leaved */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Focus_In
+ * Event sent when the window gets the focus.
+ */
+struct _Ecore_Win32_Event_Window_Focus_In
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Focus_Out
+ * Event sent when the window looses the focus.
+ */
+struct _Ecore_Win32_Event_Window_Focus_Out
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Damage
+ * Event sent when the window is damaged.
+ */
+struct _Ecore_Win32_Event_Window_Damage
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate of the top left corner of the damaged region */
+ int y; /**< The y coordinate of the top left corner of the damaged region */
+ int width; /**< The width of the damaged region */
+ int height; /**< The time the event occurred */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Create
+ * Event sent when the window is created.
+ */
+struct _Ecore_Win32_Event_Window_Create
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Destroy
+ * Event sent when the window is destroyed.
+ */
+struct _Ecore_Win32_Event_Window_Destroy
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Hide
+ * Event sent when the window is hidden.
+ */
+struct _Ecore_Win32_Event_Window_Hide
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Show
+ * Event sent when the window is shown.
+ */
+struct _Ecore_Win32_Event_Window_Show
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Configure
+ * Event sent when the window is configured.
+ */
+struct _Ecore_Win32_Event_Window_Configure
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ Ecore_Win32_Window *abovewin;
+ int x; /**< The new x coordinate of the top left corner */
+ int y; /**< The new y coordinate of the top left corner */
+ int width; /**< The new width */
+ int height; /**< The new height */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Resize
+ * Event sent when the window is resized.
+ */
+struct _Ecore_Win32_Event_Window_Resize
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ int width; /**< The new width */
+ int height; /**< The new height */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Window_Delete_Request
+ * Event sent when the window is deleted.
+ */
+struct _Ecore_Win32_Event_Window_Delete_Request
+{
+ Ecore_Win32_Window *window; /**< The window that received the event */
+ unsigned long timestamp; /**< The time the event occurred */
+};
+
+/**
+ * @typedef Ecore_Win32_Dnd_DropTarget_Callback
+ * Callback type for Drop operations. See ecore_win32_dnd_register_drop_target().
+ */
+typedef int (*Ecore_Win32_Dnd_DropTarget_Callback)(void *window, int event, int pt_x, int pt_y, void *data, int size);
+
+EAPI extern int ECORE_WIN32_EVENT_MOUSE_IN; /**< Ecore_Event for the #Ecore_Win32_Event_Mouse_In event */
+EAPI extern int ECORE_WIN32_EVENT_MOUSE_OUT; /**< Ecore_Event for the #Ecore_Win32_Event_Mouse_Out event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_IN; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Focus_In event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Focus_Out event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_DAMAGE; /**< Ecore_Event for the Ecore_Win32_Event_Damage event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_CREATE; /**< Ecore_Event for the Ecore_Win32_Event_Create event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_DESTROY; /**< Ecore_Event for the Ecore_Win32_Event_Destroy event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_HIDE; /**< Ecore_Event for the Ecore_Win32_Event_Hide event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_SHOW; /**< Ecore_Event for the Ecore_Win32_Event_Show event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_CONFIGURE; /**< Ecore_Event for the Ecore_Win32_Event_Configure event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_RESIZE; /**< Ecore_Event for the Ecore_Win32_Event_Resize event */
+EAPI extern int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Delete_Request event */
+
+
+/* Core */
+
+EAPI int ecore_win32_init();
+EAPI int ecore_win32_shutdown();
+EAPI int ecore_win32_screen_depth_get();
+EAPI void ecore_win32_double_click_time_set(double t);
+EAPI double ecore_win32_double_click_time_get(void);
+EAPI unsigned long ecore_win32_current_time_get(void);
+
+/* Window */
+
+EAPI Ecore_Win32_Window *ecore_win32_window_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+EAPI Ecore_Win32_Window *ecore_win32_window_override_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_win32_window_free(Ecore_Win32_Window *window);
+
+EAPI void *ecore_win32_window_hwnd_get(Ecore_Win32_Window *window);
+
+EAPI void ecore_win32_window_move(Ecore_Win32_Window *window,
+ int x,
+ int y);
+
+EAPI void ecore_win32_window_resize(Ecore_Win32_Window *window,
+ int width,
+ int height);
+
+EAPI void ecore_win32_window_move_resize(Ecore_Win32_Window *window,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_win32_window_geometry_get(Ecore_Win32_Window *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height);
+
+EAPI void ecore_win32_window_size_get(Ecore_Win32_Window *window,
+ int *width,
+ int *height);
+
+EAPI void ecore_win32_window_size_min_set(Ecore_Win32_Window *window,
+ unsigned int min_width,
+ unsigned int min_height);
+
+EAPI void ecore_win32_window_size_min_get(Ecore_Win32_Window *window,
+ unsigned int *min_width,
+ unsigned int *min_height);
+
+EAPI void ecore_win32_window_size_max_set(Ecore_Win32_Window *window,
+ unsigned int max_width,
+ unsigned int max_height);
+
+EAPI void ecore_win32_window_size_max_get(Ecore_Win32_Window *window,
+ unsigned int *max_width,
+ unsigned int *max_height);
+
+EAPI void ecore_win32_window_size_base_set(Ecore_Win32_Window *window,
+ unsigned int base_width,
+ unsigned int base_height);
+
+EAPI void ecore_win32_window_size_base_get(Ecore_Win32_Window *window,
+ unsigned int *base_width,
+ unsigned int *base_height);
+
+EAPI void ecore_win32_window_size_step_set(Ecore_Win32_Window *window,
+ unsigned int step_width,
+ unsigned int step_height);
+
+EAPI void ecore_win32_window_size_step_get(Ecore_Win32_Window *window,
+ unsigned int *step_width,
+ unsigned int *step_height);
+
+EAPI void ecore_win32_window_show(Ecore_Win32_Window *window);
+
+EAPI void ecore_win32_window_hide(Ecore_Win32_Window *window);
+
+EAPI void ecore_win32_window_raise(Ecore_Win32_Window *window);
+
+EAPI void ecore_win32_window_lower(Ecore_Win32_Window *window);
+
+EAPI void ecore_win32_window_title_set(Ecore_Win32_Window *window,
+ const char *title);
+
+EAPI void ecore_win32_window_focus(Ecore_Win32_Window *window);
+
+EAPI void *ecore_win32_window_focus_get(void);
+
+EAPI void ecore_win32_window_iconified_set(Ecore_Win32_Window *window,
+ Eina_Bool on);
+
+EAPI void ecore_win32_window_borderless_set(Ecore_Win32_Window *window,
+ Eina_Bool on);
+
+EAPI void ecore_win32_window_fullscreen_set(Ecore_Win32_Window *window,
+ Eina_Bool on);
+
+EAPI void ecore_win32_window_cursor_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Cursor *cursor);
+
+EAPI void ecore_win32_window_state_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_State *state,
+ unsigned int num);
+
+EAPI void ecore_win32_window_state_request_send(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_State state,
+ unsigned int set);
+
+EAPI void ecore_win32_window_type_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_Type type);
+
+/* Cursor */
+
+EAPI Ecore_Win32_Cursor *ecore_win32_cursor_new(const void *pixels_and,
+ const void *pixels_xor,
+ int width,
+ int height,
+ int hot_x,
+ int hot_y);
+
+EAPI void ecore_win32_cursor_free(Ecore_Win32_Cursor *cursor);
+
+EAPI Ecore_Win32_Cursor *ecore_win32_cursor_shaped_new(Ecore_Win32_Cursor_Shape shape);
+
+EAPI void ecore_win32_cursor_size_get(int *width, int *height);
+
+
+
+/* Drag and drop */
+EAPI int ecore_win32_dnd_init();
+EAPI int ecore_win32_dnd_shutdown();
+EAPI Eina_Bool ecore_win32_dnd_begin(const char *data,
+ int size);
+EAPI Eina_Bool ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window,
+ Ecore_Win32_Dnd_DropTarget_Callback callback);
+EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window);
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ECORE_WIN32_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32.c b/src/lib/ecore_win32/ecore_win32.c
new file mode 100644
index 0000000000..b571d74d1b
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32.c
@@ -0,0 +1,841 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <windowsx.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+/* OLE IID for Drag'n Drop */
+
+# define INITGUID
+# include <basetyps.h>
+DEFINE_OLEGUID(IID_IEnumFORMATETC, 0x00000103L, 0, 0);
+DEFINE_OLEGUID(IID_IDataObject, 0x0000010EL, 0, 0);
+DEFINE_OLEGUID(IID_IDropSource, 0x00000121L, 0, 0);
+DEFINE_OLEGUID(IID_IDropTarget, 0x00000122L, 0, 0);
+DEFINE_OLEGUID(IID_IUnknown, 0x00000000L, 0, 0);
+
+#define IDI_ICON 101
+
+static int _ecore_win32_init_count = 0;
+
+static void
+_ecore_win32_size_check(Ecore_Win32_Window *win, int w, int h, int *dx, int *dy)
+{
+ int minimal_width;
+ int minimal_height;
+
+ minimal_width = GetSystemMetrics(SM_CXMIN);
+ minimal_height = GetSystemMetrics(SM_CYMIN);
+ if ((w) < MAX(minimal_width, (int)win->min_width))
+ *dx = 0;
+ if ((w) > (int)win->max_width)
+ *dx = 0;
+ if ((h) < MAX(minimal_height, (int)win->min_height))
+ *dy = 0;
+ if ((h) > (int)win->max_height)
+ *dy = 0;
+}
+
+LRESULT CALLBACK
+_ecore_win32_window_procedure(HWND window,
+ UINT message,
+ WPARAM window_param,
+ LPARAM data_param)
+{
+ Ecore_Win32_Callback_Data *data;
+ POINTS point;
+ DWORD coord;
+
+ data = (Ecore_Win32_Callback_Data *)malloc(sizeof(Ecore_Win32_Callback_Data));
+ if (!data) return DefWindowProc(window, message, window_param, data_param);
+
+ data->window = window;
+ data->message = message;
+ data->window_param = window_param;
+ data->data_param = data_param;
+ data->timestamp = GetMessageTime();
+ coord = GetMessagePos();
+ point = MAKEPOINTS(coord);
+ data->x = point.x;
+ data->y = point.y;
+ data->discard_ctrl = EINA_FALSE;
+
+ switch (data->message)
+ {
+ /* Keyboard input notifications */
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if ((data->message == WM_KEYDOWN) &&
+ (data->window_param == VK_CONTROL) &&
+ ((HIWORD(data->data_param) & KF_EXTENDED) == 0))
+ {
+ /* Ctrl left key is pressed */
+ BOOL res;
+ MSG next_msg;
+
+ /*
+ * we check if the next message
+ * - is a WM_KEYDOWN
+ * - has the same timestamp than the Ctrl one
+ * - is the key press of the right Alt key
+ */
+ res = PeekMessage(&next_msg, data->window,
+ WM_KEYDOWN, WM_KEYDOWN,
+ PM_NOREMOVE);
+ if (res &&
+ (next_msg.wParam == VK_MENU) &&
+ (next_msg.time == data->timestamp) &&
+ (HIWORD(next_msg.lParam) & KF_EXTENDED))
+ {
+ INF("discard left Ctrl key press (sent by AltGr key press)");
+ data->discard_ctrl = EINA_TRUE;
+ }
+ }
+ _ecore_win32_event_handle_key_press(data, 1);
+ return 0;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ INF("char message");
+ _ecore_win32_event_handle_key_press(data, 0);
+ return 0;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ INF("keyup message");
+ if ((data->window_param == VK_CONTROL) &&
+ ((HIWORD(data->data_param) & KF_EXTENDED) == 0))
+ {
+ /* Ctrl left key is pressed */
+ BOOL res;
+ MSG next_msg;
+
+ /*
+ * we check if the next message
+ * - is a WM_KEYUP or WM_SYSKEYUP
+ * - has the same timestamp than the Ctrl one
+ * - is the key release of the right Alt key
+ */
+ res = PeekMessage(&next_msg, data->window,
+ WM_KEYUP, WM_SYSKEYUP,
+ PM_NOREMOVE);
+ if (res &&
+ ((next_msg.message == WM_KEYUP) ||
+ (next_msg.message == WM_SYSKEYUP)) &&
+ (next_msg.wParam == VK_MENU) &&
+ (next_msg.time == data->timestamp) &&
+ (HIWORD(next_msg.lParam) & KF_EXTENDED))
+ {
+ INF("discard left Ctrl key release (sent by AltGr key release)");
+ data->discard_ctrl = EINA_TRUE;
+ }
+ }
+ _ecore_win32_event_handle_key_release(data);
+ return 0;
+ case WM_SETFOCUS:
+ INF("setfocus message");
+ _ecore_win32_event_handle_focus_in(data);
+ return 0;
+ case WM_KILLFOCUS:
+ INF("kill focus message");
+ _ecore_win32_event_handle_focus_out(data);
+ return 0;
+ /* Mouse input notifications */
+ case WM_LBUTTONDOWN:
+ INF("left button down message");
+ SetCapture(window);
+ _ecore_win32_event_handle_button_press(data, 1);
+ return 0;
+ case WM_MBUTTONDOWN:
+ INF("middle button down message");
+ _ecore_win32_event_handle_button_press(data, 2);
+ return 0;
+ case WM_RBUTTONDOWN:
+ INF("right button down message");
+ _ecore_win32_event_handle_button_press(data, 3);
+ return 0;
+ case WM_LBUTTONUP:
+ {
+ Ecore_Win32_Window *w = NULL;
+
+ INF("left button up message");
+
+ ReleaseCapture();
+ w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA);
+ if (w->drag.dragging)
+ {
+ w->drag.dragging = 0;
+ return 0;
+ }
+
+ _ecore_win32_event_handle_button_release(data, 1);
+ return 0;
+ }
+ case WM_MBUTTONUP:
+ INF("middle button up message");
+ _ecore_win32_event_handle_button_release(data, 2);
+ return 0;
+ case WM_RBUTTONUP:
+ INF("right button up message");
+ _ecore_win32_event_handle_button_release(data, 3);
+ return 0;
+ case WM_MOUSEMOVE:
+ {
+ RECT rect;
+ Ecore_Win32_Window *w = NULL;
+
+ INF("moue move message");
+
+ w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA);
+
+ if (w->drag.dragging)
+ {
+ POINT pt;
+
+ pt.x = GET_X_LPARAM(data_param);
+ pt.y = GET_Y_LPARAM(data_param);
+ if (ClientToScreen(window, &pt))
+ {
+ if (w->drag.type == HTCAPTION)
+ {
+ int dx;
+ int dy;
+
+ dx = pt.x - w->drag.px;
+ dy = pt.y - w->drag.py;
+ ecore_win32_window_move(w, w->drag.x + dx, w->drag.y + dy);
+ w->drag.x += dx;
+ w->drag.y += dy;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTLEFT)
+ {
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ ecore_win32_window_move_resize(w, w->drag.x + dw, w->drag.y, w->drag.w - dw, w->drag.h);
+ w->drag.x += dw;
+ w->drag.w -= dw;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTRIGHT)
+ {
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ ecore_win32_window_resize(w, w->drag.w + dw, w->drag.h);
+ w->drag.w += dw;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTTOP)
+ {
+ int dh;
+
+ dh = pt.y - w->drag.py;
+ ecore_win32_window_move_resize(w, w->drag.x, w->drag.y + dh, w->drag.w, w->drag.h - dh);
+ w->drag.y += dh;
+ w->drag.h -= dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTBOTTOM)
+ {
+ int dh;
+
+ dh = pt.y - w->drag.py;
+ ecore_win32_window_resize(w, w->drag.w, w->drag.h + dh);
+ w->drag.h += dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTTOPLEFT)
+ {
+ int dx;
+ int dy;
+ int dh;
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ dh = pt.y - w->drag.py;
+ dx = dw;
+ dy = dh;
+ _ecore_win32_size_check(w,
+ w->drag.w - dw, w->drag.h - dh,
+ &dx, &dy);
+
+ ecore_win32_window_move_resize(w, w->drag.x + dx, w->drag.y + dy, w->drag.w - dw, w->drag.h - dh);
+ w->drag.x += dx;
+ w->drag.y += dy;
+ w->drag.w -= dw;
+ w->drag.h -= dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTTOPRIGHT)
+ {
+ int dx;
+ int dy;
+ int dh;
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ dh = pt.y - w->drag.py;
+ dx = dw;
+ dy = dh;
+ _ecore_win32_size_check(w,
+ w->drag.w, w->drag.h - dh,
+ &dx, &dy);
+ ecore_win32_window_move_resize(w, w->drag.x, w->drag.y + dy, w->drag.w, w->drag.h - dh);
+ w->drag.y += dy;
+ w->drag.w += dw;
+ w->drag.h -= dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTBOTTOMLEFT)
+ {
+ int dx;
+ int dy;
+ int dh;
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ dh = pt.y - w->drag.py;
+ dx = dw;
+ dy = dh;
+ _ecore_win32_size_check(w,
+ w->drag.w - dw, w->drag.h + dh,
+ &dx, &dy);
+ ecore_win32_window_move_resize(w, w->drag.x + dx, w->drag.y, w->drag.w - dw, w->drag.h + dh);
+ w->drag.x += dx;
+ w->drag.w -= dw;
+ w->drag.h += dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ if (w->drag.type == HTBOTTOMRIGHT)
+ {
+ int dh;
+ int dw;
+
+ dw = pt.x - w->drag.px;
+ dh = pt.y - w->drag.py;
+ ecore_win32_window_resize(w, w->drag.w + dw, w->drag.h + dh);
+ w->drag.w += dw;
+ w->drag.h += dh;
+ w->drag.px = pt.x;
+ w->drag.py = pt.y;
+ return 0;
+ }
+ }
+ }
+
+ if (GetClientRect(window, &rect))
+ {
+ POINT pt;
+
+ INF("mouse in window");
+
+ pt.x = GET_X_LPARAM(data_param);
+ pt.y = GET_Y_LPARAM(data_param);
+ if (!PtInRect(&rect, pt))
+ {
+ if (w->pointer_is_in)
+ {
+ w->pointer_is_in = 0;
+ _ecore_win32_event_handle_leave_notify(data);
+ }
+ }
+ else
+ {
+ if (!w->pointer_is_in)
+ {
+ w->pointer_is_in = 1;
+ _ecore_win32_event_handle_enter_notify(data);
+ }
+ }
+ }
+ else
+ {
+ ERR("GetClientRect() failed");
+ }
+ _ecore_win32_event_handle_motion_notify(data);
+
+ return 0;
+ }
+ case WM_MOUSEWHEEL:
+ INF("mouse wheel message");
+ _ecore_win32_event_handle_button_press(data, 4);
+ return 0;
+ /* Window notifications */
+ case WM_CREATE:
+ INF("create window message");
+ _ecore_win32_event_handle_create_notify(data);
+ return 0;
+ case WM_DESTROY:
+ INF("destroy window message");
+ _ecore_win32_event_handle_destroy_notify(data);
+ return 0;
+ case WM_SHOWWINDOW:
+ INF("show window message");
+ if ((data->data_param == SW_OTHERUNZOOM) ||
+ (data->data_param == SW_OTHERZOOM))
+ return 0;
+
+ if (data->window_param)
+ _ecore_win32_event_handle_map_notify(data);
+ else
+ _ecore_win32_event_handle_unmap_notify(data);
+
+ return 0;
+ case WM_CLOSE:
+ INF("close window message");
+ _ecore_win32_event_handle_delete_request(data);
+ return 0;
+ case WM_GETMINMAXINFO:
+ INF("get min max info window message");
+ return TRUE;
+ case WM_MOVING:
+ INF("moving window message");
+ _ecore_win32_event_handle_configure_notify(data);
+ return TRUE;
+ case WM_MOVE:
+ INF("move window message");
+ return 0;
+ case WM_SIZING:
+ INF("sizing window message");
+ _ecore_win32_event_handle_resize(data);
+ _ecore_win32_event_handle_configure_notify(data);
+ return TRUE;
+ case WM_SIZE:
+ INF("size window message");
+ return 0;
+/* case WM_WINDOWPOSCHANGING: */
+/* { */
+/* RECT rect; */
+/* GetClientRect(window, &rect); */
+/* printf (" *** ecore message : WINDOWPOSCHANGING %ld %ld\n", */
+/* rect.right - rect.left, rect.bottom - rect.top); */
+/* } */
+/* _ecore_win32_event_handle_configure_notify(data); */
+/* return 0; */
+ case WM_WINDOWPOSCHANGED:
+ INF("position changed window message");
+ _ecore_win32_event_handle_configure_notify(data);
+ _ecore_win32_event_handle_expose(data);
+ return 0;
+ case WM_ENTERSIZEMOVE:
+ INF("enter size move window message");
+ return 0;
+ case WM_EXITSIZEMOVE:
+ INF("exit size move window message");
+ return 0;
+ case WM_NCLBUTTONDOWN:
+ INF("non client left button down window message");
+
+ if (((DWORD)window_param == HTCAPTION) ||
+ ((DWORD)window_param == HTBOTTOM) ||
+ ((DWORD)window_param == HTBOTTOMLEFT) ||
+ ((DWORD)window_param == HTBOTTOMRIGHT) ||
+ ((DWORD)window_param == HTLEFT) ||
+ ((DWORD)window_param == HTRIGHT) ||
+ ((DWORD)window_param == HTTOP) ||
+ ((DWORD)window_param == HTTOPLEFT) ||
+ ((DWORD)window_param == HTTOPRIGHT))
+ {
+ Ecore_Win32_Window *w;
+
+ w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA);
+ ecore_win32_window_geometry_get(w,
+ NULL, NULL,
+ &w->drag.w, &w->drag.h);
+ SetCapture(window);
+ w->drag.type = (DWORD)window_param;
+ w->drag.px = GET_X_LPARAM(data_param);
+ w->drag.py = GET_Y_LPARAM(data_param);
+ w->drag.dragging = 1;
+ return 0;
+ }
+ return DefWindowProc(window, message, window_param, data_param);
+ case WM_SYSCOMMAND:
+ INF("sys command window message %d", (int)window_param);
+
+ if ((((DWORD)window_param & 0xfff0) == SC_MOVE) ||
+ (((DWORD)window_param & 0xfff0) == SC_SIZE))
+ {
+ Ecore_Win32_Window *w;
+
+ INF("sys command MOVE or SIZE window message : %dx%d", GET_X_LPARAM(data_param), GET_Y_LPARAM(data_param));
+
+ w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA);
+ w->drag.dragging = 1;
+ return 0;
+ }
+ return DefWindowProc(window, message, window_param, data_param);
+ /* GDI notifications */
+ case WM_ERASEBKGND:
+ return 1;
+ case WM_PAINT:
+ {
+ RECT rect;
+
+ INF("paint message");
+
+ if (GetUpdateRect(window, &rect, FALSE))
+ {
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ hdc = BeginPaint(window, &ps);
+ data->update = rect;
+ _ecore_win32_event_handle_expose(data);
+ EndPaint(window, &ps);
+ }
+ return 0;
+ }
+ case WM_SETREDRAW:
+ INF("set redraw message");
+ return 0;
+ case WM_SYNCPAINT:
+ INF("sync paint message");
+ return 0;
+ default:
+ return DefWindowProc(window, message, window_param, data_param);
+ }
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+
+HINSTANCE _ecore_win32_instance = NULL;
+double _ecore_win32_double_click_time = 0.25;
+unsigned long _ecore_win32_event_last_time = 0;
+Ecore_Win32_Window *_ecore_win32_event_last_window = NULL;
+int _ecore_win32_log_dom_global = -1;
+
+int ECORE_WIN32_EVENT_MOUSE_IN = 0;
+int ECORE_WIN32_EVENT_MOUSE_OUT = 0;
+int ECORE_WIN32_EVENT_WINDOW_FOCUS_IN = 0;
+int ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT = 0;
+int ECORE_WIN32_EVENT_WINDOW_DAMAGE = 0;
+int ECORE_WIN32_EVENT_WINDOW_CREATE = 0;
+int ECORE_WIN32_EVENT_WINDOW_DESTROY = 0;
+int ECORE_WIN32_EVENT_WINDOW_SHOW = 0;
+int ECORE_WIN32_EVENT_WINDOW_HIDE = 0;
+int ECORE_WIN32_EVENT_WINDOW_CONFIGURE = 0;
+int ECORE_WIN32_EVENT_WINDOW_RESIZE = 0;
+int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = 0;
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_Win32_Group Ecore_Win32 library
+ *
+ * Ecore_Win32 is a library that wraps Windows graphic functions
+ * and integrate them nicely into the Ecore main loop.
+ *
+ * @section Ecore_Win32_Sec_Init Initialisation / Shutdown
+ *
+ * To fill...
+ *
+ * @section Ecore_Win32_Sec_Icons How to set icons to an application
+ *
+ * It is possible to also sets the icon of the application easily:
+ *
+ * @li Create an icon with your favorite image creator. The Gimp is a
+ * good choice. Create several images of size 16, 32 and 48. You can
+ * also create images of size 24, 64, 128 and 256. Paste all of them
+ * in the image of size 16 as a layer. Save the image of size 16 with
+ * the name my_icon.ico. Put it where the source code of the
+ * application is located.
+ * @li Create my_icon_rc.rc file with your code editor and add in it:
+ * @code
+ * 101 ICON DISCARDABLE "my_icon.ico"
+ * @endcode
+ * @li With Visual Studio, put that file in the 'Resource file' part
+ * of the project.
+ * @li With MinGW, you have to compile it with windres:
+ * @code
+ * windres my_icon_rc.rc my_icon_rc.o
+ * @endcode
+ * and add my_icon_rc.o to the object files of the application.
+ *
+ * @note The value 101 must not be changed, it's the ID used
+ * internally by Ecore_Win32 to get the icons.
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize the Ecore_Win32 library.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up the Windows graphic system. It returns 0 on
+ * failure, otherwise it returns the number of times it has already been
+ * called.
+ *
+ * When Ecore_Win32 is not used anymore, call ecore_win32_shutdown()
+ * to shut down the Ecore_Win32 library.
+ */
+EAPI int
+ecore_win32_init()
+{
+ WNDCLASSEX wc;
+ HICON icon;
+ HICON icon_sm;
+
+ if (++_ecore_win32_init_count != 1)
+ return _ecore_win32_init_count;
+
+ if (!eina_init())
+ return --_ecore_win32_init_count;
+
+ _ecore_win32_log_dom_global = eina_log_domain_register
+ ("ecore_win32", ECORE_WIN32_DEFAULT_LOG_COLOR);
+ if (_ecore_win32_log_dom_global < 0)
+ {
+ EINA_LOG_ERR("Ecore_Win32: Could not register log domain");
+ goto shutdown_eina;
+ }
+
+ if (!ecore_event_init())
+ {
+ ERR("Ecore_Win32: Could not init ecore_event");
+ goto unregister_log_domain;
+ }
+
+ _ecore_win32_instance = GetModuleHandle(NULL);
+ if (!_ecore_win32_instance)
+ {
+ ERR("GetModuleHandle() failed");
+ goto shutdown_ecore_event;
+ }
+
+ icon = LoadImage(_ecore_win32_instance,
+ MAKEINTRESOURCE(IDI_ICON),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXICON),
+ GetSystemMetrics(SM_CYICON),
+ LR_DEFAULTCOLOR);
+ icon_sm = LoadImage(_ecore_win32_instance,
+ MAKEINTRESOURCE(IDI_ICON),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON),
+ LR_DEFAULTCOLOR);
+ if (!icon)
+ icon = LoadIcon (NULL, IDI_APPLICATION);
+ if (!icon_sm)
+ icon_sm = LoadIcon (NULL, IDI_APPLICATION);
+
+ memset (&wc, 0, sizeof (WNDCLASSEX));
+ wc.cbSize = sizeof (WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = _ecore_win32_window_procedure;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = _ecore_win32_instance;
+ wc.hIcon = icon;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = ECORE_WIN32_WINDOW_CLASS;
+ wc.hIconSm = icon_sm;
+
+ if(!RegisterClassEx(&wc))
+ {
+ ERR("RegisterClass() failed");
+ goto free_library;
+ }
+
+ if (!ecore_win32_dnd_init())
+ {
+ ERR("ecore_win32_dnd_init() failed");
+ goto unregister_class;
+ }
+
+ if (!ECORE_WIN32_EVENT_MOUSE_IN)
+ {
+ ECORE_WIN32_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_WIN32_EVENT_MOUSE_OUT = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_DAMAGE = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_CREATE = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_DESTROY = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_SHOW = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_HIDE = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_RESIZE = ecore_event_type_new();
+ ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
+ }
+
+ return _ecore_win32_init_count;
+
+ unregister_class:
+ UnregisterClass(ECORE_WIN32_WINDOW_CLASS, _ecore_win32_instance);
+ free_library:
+ FreeLibrary(_ecore_win32_instance);
+ shutdown_ecore_event:
+ ecore_event_shutdown();
+ unregister_log_domain:
+ eina_log_domain_unregister(_ecore_win32_log_dom_global);
+ shutdown_eina:
+ eina_shutdown();
+
+ return --_ecore_win32_init_count;
+}
+
+/**
+ * @brief Shut down the Ecore_Win32 library.
+ *
+ * @return 0 when the library is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Ecore_Win32 library. It returns 0 when it has
+ * been called the same number of times than ecore_win32_init(). In that case
+ * it shuts down all the Windows graphic system.
+ */
+EAPI int
+ecore_win32_shutdown()
+{
+ if (--_ecore_win32_init_count != 0)
+ return _ecore_win32_init_count;
+
+ ecore_win32_dnd_shutdown();
+
+ if (!UnregisterClass(ECORE_WIN32_WINDOW_CLASS, _ecore_win32_instance))
+ INF("UnregisterClass() failed");
+
+ if (!FreeLibrary(_ecore_win32_instance))
+ INF("FreeLibrary() failed");
+
+ _ecore_win32_instance = NULL;
+
+ ecore_event_shutdown();
+ eina_log_domain_unregister(_ecore_win32_log_dom_global);
+ _ecore_win32_log_dom_global = -1;
+ eina_shutdown();
+
+ return _ecore_win32_init_count;
+}
+
+/**
+ * @brief Retrieve the depth of the screen.
+ *
+ * @return The depth of the screen.
+ *
+ * This function returns the depth of the screen. If an error occurs,
+ * it returns 0.
+ */
+EAPI int
+ecore_win32_screen_depth_get()
+{
+ HDC dc;
+ int depth;
+
+ INF("getting screen depth");
+
+ dc = GetDC(NULL);
+ if (!dc)
+ {
+ ERR("GetDC() failed");
+ return 0;
+ }
+
+ depth = GetDeviceCaps(dc, BITSPIXEL);
+ if (!ReleaseDC(NULL, dc))
+ {
+ ERR("ReleaseDC() failed (device context not released)");
+ }
+
+ return depth;
+}
+
+/**
+ * @brief Sets the timeout for a double and triple clicks to be flagged.
+ *
+ * @param t The time in seconds.
+ *
+ * This function sets the time @p t between clicks before the
+ * double_click flag is set in a button down event. If 3 clicks occur
+ * within double this time, the triple_click flag is also set.
+ */
+EAPI void
+ecore_win32_double_click_time_set(double t)
+{
+ if (t < 0.0) t = 0.0;
+ _ecore_win32_double_click_time = t;
+}
+
+/**
+ * @brief Retrieve the double and triple click flag timeout.
+ *
+ * @return The timeout for double clicks in seconds.
+ *
+ * This function returns the double clicks in seconds. If
+ * ecore_win32_double_click_time_set() has not been called, the
+ * default value is returned. See ecore_win32_double_click_time_set()
+ * for more informations.
+ */
+EAPI double
+ecore_win32_double_click_time_get(void)
+{
+ return _ecore_win32_double_click_time;
+}
+
+/**
+ * @brief Return the last event time.
+ *
+ * @return The last envent time.
+ *
+ * This function returns the last event time.
+ */
+EAPI unsigned long
+ecore_win32_current_time_get(void)
+{
+ return _ecore_win32_event_last_time;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_win32/ecore_win32_cursor.c b/src/lib/ecore_win32/ecore_win32_cursor.c
new file mode 100644
index 0000000000..9b58c95160
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_cursor.c
@@ -0,0 +1,305 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Eina.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_Win32_Group Ecore_Win32 library
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new cursor.
+ *
+ * @param pixels_and The array of bytes containing the bit values for
+ * the AND mask of the cursor.
+ * @param pixels_xor The array of bytes containing the bit values for
+ * the XOR mask of the cursor.
+ * @param width The width of the cursor.
+ * @param height The height of the cursor.
+ * @param hot_x The horizontal position of the cursor's hot spot.
+ * @param hot_y The vertical position of the cursor's hot spot.
+ * @return A newly user-defined cursor.
+ *
+ * This function creates a new cursor of size @p width and @p
+ * height. They must be valid size. To determine the valid size of a
+ * cursor, use ecore_win32_cursor_size_get(). @p pixels_and is an array
+ * of bytes (unsigned char) containing the bits of the cursor that
+ * will be visible. @p pixels_xor is similar but will allow the cursor
+ * to have a shape. Here is the truth table for the masks:
+ *
+ * <table border=1>
+ * <tr><td>AND mask</td><td>XOR mask</td><td>Display</td></tr>
+ * <tr><td>0</td> <td>0</td> <td>Black</td></tr>
+ * <tr><td>0</td> <td>1</td> <td>White</td></tr>
+ * <tr><td>1</td> <td>0</td> <td>Screen</td></tr>
+ * <tr><td>1</td> <td>1</td> <td>Reverse screen</td></tr>
+ * </table>
+ *
+ * @p hot_x and @p hot_y are the position of the hot spot of the
+ * cursor. If @p pixels_and or @p pixels_xor are @c NULL, the function
+ * returns NULL. If @p width or @p height does not match the valid
+ * size of a cursor, the function returns @c NULL. On success, the
+ * function creates a user-defined cursor, otherwise it returns
+ * @c NULL.
+ *
+ * Once the cursor is not used anymore, use ecore_win32_cursor_free()
+ * to free the ressources.
+ *
+ * Example of use:
+ *
+ * @code
+ * unsigned char pixels_and[] ={
+ * 0xFF, 0xFC, 0x3F, 0xFF, // line 1
+ * 0xFF, 0xC0, 0x1F, 0xFF, // line 2
+ * 0xFF, 0x00, 0x3F, 0xFF, // line 3
+ * 0xFE, 0x00, 0xFF, 0xFF, // line 4
+ *
+ * 0xF7, 0x01, 0xFF, 0xFF, // line 5
+ * 0xF0, 0x03, 0xFF, 0xFF, // line 6
+ * 0xF0, 0x03, 0xFF, 0xFF, // line 7
+ * 0xE0, 0x07, 0xFF, 0xFF, // line 8
+ *
+ * 0xC0, 0x07, 0xFF, 0xFF, // line 9
+ * 0xC0, 0x0F, 0xFF, 0xFF, // line 10
+ * 0x80, 0x0F, 0xFF, 0xFF, // line 11
+ * 0x80, 0x0F, 0xFF, 0xFF, // line 12
+ *
+ * 0x80, 0x07, 0xFF, 0xFF, // line 13
+ * 0x00, 0x07, 0xFF, 0xFF, // line 14
+ * 0x00, 0x03, 0xFF, 0xFF, // line 15
+ * 0x00, 0x00, 0xFF, 0xFF, // line 16
+ *
+ * 0x00, 0x00, 0x7F, 0xFF, // line 17
+ * 0x00, 0x00, 0x1F, 0xFF, // line 18
+ * 0x00, 0x00, 0x0F, 0xFF, // line 19
+ * 0x80, 0x00, 0x0F, 0xFF, // line 20
+ *
+ * 0x80, 0x00, 0x07, 0xFF, // line 21
+ * 0x80, 0x00, 0x07, 0xFF, // line 22
+ * 0xC0, 0x00, 0x07, 0xFF, // line 23
+ * 0xC0, 0x00, 0x0F, 0xFF, // line 24
+ *
+ * 0xE0, 0x00, 0x0F, 0xFF, // line 25
+ * 0xF0, 0x00, 0x1F, 0xFF, // line 26
+ * 0xF0, 0x00, 0x1F, 0xFF, // line 27
+ * 0xF8, 0x00, 0x3F, 0xFF, // line 28
+ *
+ * 0xFE, 0x00, 0x7F, 0xFF, // line 29
+ * 0xFF, 0x00, 0xFF, 0xFF, // line 30
+ * 0xFF, 0xC3, 0xFF, 0xFF, // line 31
+ * 0xFF, 0xFF, 0xFF, 0xFF // line 32
+ * };
+ *
+ * unsigned char pixels_xor[] = {
+ * 0x00, 0x00, 0x00, 0x00, // line 1
+ * 0x00, 0x03, 0xC0, 0x00, // line 2
+ * 0x00, 0x3F, 0x00, 0x00, // line 3
+ * 0x00, 0xFE, 0x00, 0x00, // line 4
+ *
+ * 0x0E, 0xFC, 0x00, 0x00, // line 5
+ * 0x07, 0xF8, 0x00, 0x00, // line 6
+ * 0x07, 0xF8, 0x00, 0x00, // line 7
+ * 0x0F, 0xF0, 0x00, 0x00, // line 8
+ *
+ * 0x1F, 0xF0, 0x00, 0x00, // line 9
+ * 0x1F, 0xE0, 0x00, 0x00, // line 10
+ * 0x3F, 0xE0, 0x00, 0x00, // line 11
+ * 0x3F, 0xE0, 0x00, 0x00, // line 12
+ *
+ * 0x3F, 0xF0, 0x00, 0x00, // line 13
+ * 0x7F, 0xF0, 0x00, 0x00, // line 14
+ * 0x7F, 0xF8, 0x00, 0x00, // line 15
+ * 0x7F, 0xFC, 0x00, 0x00, // line 16
+ *
+ * 0x7F, 0xFF, 0x00, 0x00, // line 17
+ * 0x7F, 0xFF, 0x80, 0x00, // line 18
+ * 0x7F, 0xFF, 0xE0, 0x00, // line 19
+ * 0x3F, 0xFF, 0xE0, 0x00, // line 20
+ *
+ * 0x3F, 0xC7, 0xF0, 0x00, // line 21
+ * 0x3F, 0x83, 0xF0, 0x00, // line 22
+ * 0x1F, 0x83, 0xF0, 0x00, // line 23
+ * 0x1F, 0x83, 0xE0, 0x00, // line 24
+ *
+ * 0x0F, 0xC7, 0xE0, 0x00, // line 25
+ * 0x07, 0xFF, 0xC0, 0x00, // line 26
+ * 0x07, 0xFF, 0xC0, 0x00, // line 27
+ * 0x01, 0xFF, 0x80, 0x00, // line 28
+ *
+ * 0x00, 0xFF, 0x00, 0x00, // line 29
+ * 0x00, 0x3C, 0x00, 0x00, // line 30
+ * 0x00, 0x00, 0x00, 0x00, // line 31
+ * 0x00, 0x00, 0x00, 0x00 // line 32
+ * };
+ *
+ * Ecore_Win32_Cursor *cursor = ecore_win32_cursor_new(pixels_and, pixels_xor, 32, 32, 19, 2);
+ * @endcode
+ */
+EAPI Ecore_Win32_Cursor *
+ecore_win32_cursor_new(const void *pixels_and,
+ const void *pixels_xor,
+ int width,
+ int height,
+ int hot_x,
+ int hot_y)
+{
+ Ecore_Win32_Cursor *cursor = NULL;
+ int cursor_width;
+ int cursor_height;
+
+ INF("creating cursor");
+
+ if (!pixels_and || !pixels_xor)
+ return NULL;
+
+ cursor_width = GetSystemMetrics(SM_CXCURSOR);
+ cursor_height = GetSystemMetrics(SM_CYCURSOR);
+
+ if ((cursor_width != width) ||
+ (cursor_height != height))
+ return NULL;
+
+ if (!(cursor = CreateCursor(_ecore_win32_instance,
+ hot_x, hot_y,
+ width, height,
+ pixels_and,
+ pixels_xor)))
+ return NULL;
+
+ return cursor;
+}
+
+/**
+ * @brief Free the given cursor.
+ *
+ * @param cursor The cursor to free.
+ *
+ * This function free @p cursor. @p cursor must have been obtained
+ * with ecore_win32_cursor_new().
+ */
+EAPI void
+ecore_win32_cursor_free(Ecore_Win32_Cursor *cursor)
+{
+ INF("destroying cursor");
+
+ DestroyCursor(cursor);
+}
+
+/**
+ * @brief Create a cursor from a Windows ressource.
+ *
+ * @param shape The pre-defined shape of the cursor.
+ * @return The new cursor.
+ *
+ * This function returns a pre-defined cursor with a specified
+ * @p shape. This cursor does not need to be freed, as it is loaded
+ * from an existing resource.
+ */
+EAPI Ecore_Win32_Cursor *
+ecore_win32_cursor_shaped_new(Ecore_Win32_Cursor_Shape shape)
+{
+ Ecore_Win32_Cursor *cursor = NULL;
+ const char *cursor_name;
+
+ INF("geting shape cursor");
+
+ switch (shape)
+ {
+ case ECORE_WIN32_CURSOR_SHAPE_APP_STARTING:
+ cursor_name = IDC_APPSTARTING;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_ARROW:
+ cursor_name = IDC_ARROW;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_CROSS:
+ cursor_name = IDC_CROSS;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_HAND:
+ cursor_name = IDC_HAND;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_HELP:
+ cursor_name = IDC_HELP;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_I_BEAM:
+ cursor_name = IDC_IBEAM;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_NO:
+ cursor_name = IDC_NO;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_SIZE_ALL:
+ cursor_name = IDC_SIZEALL;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_SIZE_NESW:
+ cursor_name = IDC_SIZENESW;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_SIZE_NS:
+ cursor_name = IDC_SIZENS;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_SIZE_NWSE:
+ cursor_name = IDC_SIZENWSE;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_SIZE_WE:
+ cursor_name = IDC_SIZEWE;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_UP_ARROW:
+ cursor_name = IDC_UPARROW;
+ break;
+ case ECORE_WIN32_CURSOR_SHAPE_WAIT:
+ cursor_name = IDC_WAIT;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (!(cursor = LoadCursor(NULL, cursor_name)))
+ return NULL;
+
+ return cursor;
+}
+
+/**
+ * @brief Retrieve the size of a valid cursor.
+ *
+ * @param width The width of a valid cursor.
+ * @param height The height of a valid cursor.
+ *
+ * This function returns the size of a cursor that must be passed to
+ * ecore_win32_cursor_new(). @p width and @p height are buffers that
+ * will be filled with the correct size. They can be @c NULL.
+ */
+EAPI void
+ecore_win32_cursor_size_get(int *width, int *height)
+{
+ INF("geting size cursor");
+
+ if (*width) *width = GetSystemMetrics(SM_CXCURSOR);
+ if (*height) *height = GetSystemMetrics(SM_CYCURSOR);
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_win32/ecore_win32_dnd.c b/src/lib/ecore_win32/ecore_win32_dnd.c
new file mode 100755
index 0000000000..6c5253ae20
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd.c
@@ -0,0 +1,221 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+
+static int _ecore_win32_dnd_init_count = 0;
+
+static HANDLE DataToHandle(const char *data, int size)
+{
+ char *ptr;
+ ptr = (char *)GlobalAlloc(GMEM_FIXED, size);
+ memcpy(ptr, data, size);
+ return ptr;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_Win32_Group Ecore_Win32 library
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize the Ecore_Win32 Drag and Drop module.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function initialize the Drag and Drop module. It returns 0 on
+ * failure, otherwise it returns the number of times it has already
+ * been called.
+ *
+ * When the Drag and Drop module is not used anymore, call
+ * ecore_win32_dnd_shutdown() to shut down the module.
+ */
+EAPI int
+ecore_win32_dnd_init()
+{
+ if (_ecore_win32_dnd_init_count > 0)
+ {
+ _ecore_win32_dnd_init_count++;
+ return _ecore_win32_dnd_init_count;
+ }
+
+ if (OleInitialize(NULL) != S_OK)
+ return 0;
+
+ _ecore_win32_dnd_init_count++;
+
+ return _ecore_win32_dnd_init_count;
+}
+
+/**
+ * @brief Shut down the Ecore_Win32 Drag and Drop module.
+ *
+ * @return 0 when the module is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Drag and Drop module. It returns 0 when it has
+ * been called the same number of times than ecore_win32_dnd_init(). In that case
+ * it shut down the module.
+ */
+EAPI int
+ecore_win32_dnd_shutdown()
+{
+ _ecore_win32_dnd_init_count--;
+ if (_ecore_win32_dnd_init_count > 0) return _ecore_win32_dnd_init_count;
+
+ OleUninitialize();
+
+ if (_ecore_win32_dnd_init_count < 0) _ecore_win32_dnd_init_count = 0;
+
+ return _ecore_win32_dnd_init_count;
+}
+
+/**
+ * @brief Begin a DnD operation.
+ *
+ * @param data The name pf the Drag operation.
+ * @param size The size of the name.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function start a Drag operation with the name @p data. If
+ * @p data is @c NULL, @c EINA_FALSE is returned. if @p size is less than
+ * @c 0, it is set to the length (as strlen()) of @p data. On success the
+ * function returns @c EINA_TRUE, otherwise it returns @c EINA_FALSE.
+ */
+EAPI Eina_Bool
+ecore_win32_dnd_begin(const char *data,
+ int size)
+{
+ IDataObject *pDataObject = NULL;
+ IDropSource *pDropSource = NULL;
+ FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 };
+ Eina_Bool res = EINA_FALSE;
+
+ if (!data)
+ return EINA_FALSE;
+
+ if (size < 0)
+ size = strlen(data) + 1;
+
+ stgmed.hGlobal = DataToHandle(data, size);
+
+ // create the data object
+ pDataObject = (IDataObject *)_ecore_win32_dnd_data_object_new((void *)&fmtetc,
+ (void *)&stgmed,
+ 1);
+ pDropSource = (IDropSource *)_ecore_win32_dnd_drop_source_new();
+
+ if (pDataObject && pDropSource)
+ {
+ DWORD dwResult;
+ DWORD dwEffect = DROPEFFECT_COPY;
+
+ // do the drag-drop!
+ dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);
+
+ // finished. Check the return values to see if we need to do anything else
+ if (dwResult == DRAGDROP_S_DROP)
+ {
+ //printf(">>> \"%s\" Dropped <<<\n", str);
+ if(dwEffect == DROPEFFECT_MOVE)
+ {
+ // remove the data we just dropped from active document
+ }
+ }
+ //else if (dwResult == DRAGDROP_S_CANCEL)
+ // printf("DND cancelled\n");
+ //else
+ // printf("DND error\n");
+
+ res = EINA_TRUE;
+ }
+
+ _ecore_win32_dnd_data_object_free(pDataObject);
+ _ecore_win32_dnd_drop_source_free(pDropSource);
+
+ // cleanup
+ ReleaseStgMedium(&stgmed);
+
+ return res;
+}
+
+/**
+ * @brief Register a Drop operation.
+ *
+ * @param window The destination of the Drop operation.
+ * @param callback The callback called when the Drop operation
+ * finishes.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function register a Drop operation on @p window. Once the Drop
+ * operation finishes, @p callback is called. If @p window is @c NULL,
+ * the function returns @c EINA_FALSE. On success, it returns @c EINA_TRUE,
+ * otherwise it returns @c EINA_FALSE.
+ */
+EAPI Eina_Bool
+ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window,
+ Ecore_Win32_Dnd_DropTarget_Callback callback)
+{
+ Ecore_Win32_Window *wnd = (Ecore_Win32_Window *)window;
+
+ if (!window)
+ return EINA_FALSE;
+
+ wnd->dnd_drop_target = _ecore_win32_dnd_register_drop_window(wnd->window,
+ callback,
+ (void *)wnd);
+ return wnd->dnd_drop_target ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Unregister a Drop operation.
+ *
+ * @param window The destination of the Drop operation.
+ *
+ * This function unregister a Drop operation on @p window. If
+ * @p window is @c NULL, the function does nothing.
+ */
+EAPI void
+ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window)
+{
+ Ecore_Win32_Window *wnd = (Ecore_Win32_Window *)window;
+
+ if (!window)
+ return;
+
+ if (wnd->dnd_drop_target)
+ _ecore_win32_dnd_unregister_drop_window(wnd->window, wnd->dnd_drop_target);
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp b/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp
new file mode 100644
index 0000000000..213197780b
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp
@@ -0,0 +1,209 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <ole2.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+#include "ecore_win32_dnd_enumformatetc.h"
+#include "ecore_win32_dnd_data_object.h"
+
+
+static HGLOBAL DupGlobalMem(HGLOBAL hMem)
+{
+ DWORD len = (DWORD)GlobalSize(hMem);
+ PVOID source = GlobalLock(hMem);
+ PVOID dest = GlobalAlloc(GMEM_FIXED, len);
+ memcpy(dest, source, len);
+ GlobalUnlock(hMem);
+ return dest;
+}
+
+// structors
+
+DataObject::DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
+{
+ assert(fmtetc != NULL);
+ assert(stgmed != NULL);
+ assert(count > 0);
+
+ // reference count must ALWAYS start at 1
+ ref_count_ = 1;
+ formats_num_ = count;
+
+ format_etc_ = new FORMATETC[count];
+ stg_medium_ = new STGMEDIUM[count];
+
+ for(int i = 0; i < count; i++)
+ {
+ format_etc_[i] = fmtetc[i];
+ stg_medium_[i] = stgmed[i];
+ }
+}
+
+DataObject::~DataObject()
+{
+ delete[] format_etc_;
+ delete[] stg_medium_;
+}
+
+
+// IUnknown
+
+HRESULT DataObject::QueryInterface(REFIID iid, void **ppvObject)
+{
+ // check to see what interface has been requested
+ if ((iid == IID_IDataObject) || (iid == IID_IUnknown))
+ {
+ AddRef();
+ *ppvObject = this;
+ return S_OK;
+ }
+ *ppvObject = 0;
+ return E_NOINTERFACE;
+}
+
+ULONG DataObject::AddRef()
+{
+ return InterlockedIncrement(&ref_count_);
+}
+
+ULONG DataObject::Release()
+{
+ LONG count = InterlockedDecrement(&ref_count_);
+ if(count == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return count;
+}
+
+// IDataObject
+
+HRESULT DataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
+{
+ assert(pMedium != NULL);
+ int idx;
+
+ // try to match the specified FORMATETC with one of our supported formats
+ if((idx = lookup_format_etc(pFormatEtc)) == -1)
+ return DV_E_FORMATETC;
+
+ // found a match - transfer data into supplied storage medium
+ pMedium->tymed = format_etc_[idx].tymed;
+ pMedium->pUnkForRelease = 0;
+
+ // copy the data into the caller's storage medium
+ switch(format_etc_[idx].tymed)
+ {
+ case TYMED_HGLOBAL:
+ pMedium->hGlobal = DupGlobalMem(stg_medium_[idx].hGlobal);
+ break;
+
+ default:
+ return DV_E_FORMATETC;
+ }
+
+ return S_OK;
+}
+
+HRESULT DataObject::GetDataHere(FORMATETC *pFormatEtc EINA_UNUSED, STGMEDIUM *pmedium EINA_UNUSED)
+{
+ return DATA_E_FORMATETC;
+}
+
+HRESULT DataObject::QueryGetData(FORMATETC *pFormatEtc)
+{
+ return (lookup_format_etc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
+}
+
+HRESULT DataObject::GetCanonicalFormatEtc(FORMATETC *pFormatEct EINA_UNUSED, FORMATETC *pFormatEtcOut)
+{
+ // Apparently we have to set this field to NULL even though we don't do anything else
+ pFormatEtcOut->ptd = NULL;
+ return E_NOTIMPL;
+}
+
+HRESULT DataObject::SetData(FORMATETC *pFormatEtc EINA_UNUSED, STGMEDIUM *pMedium EINA_UNUSED, BOOL fRelease EINA_UNUSED)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT DataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
+{
+ // only the get direction is supported for OLE
+ if(dwDirection == DATADIR_GET)
+ {
+ // for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however
+ // to support all Windows platforms we need to implement IEnumFormatEtc ourselves.
+ return CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
+ }
+ else
+ {
+ // the direction specified is not supported for drag+drop
+ return E_NOTIMPL;
+ }
+}
+
+HRESULT DataObject::DAdvise(FORMATETC *pFormatEtc EINA_UNUSED, DWORD advf EINA_UNUSED, IAdviseSink *, DWORD *)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+HRESULT DataObject::DUnadvise(DWORD dwConnection EINA_UNUSED)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+HRESULT DataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise EINA_UNUSED)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+// internal helper function
+
+int DataObject::lookup_format_etc(FORMATETC *pFormatEtc)
+{
+ // check each of our formats in turn to see if one matches
+ for(int i = 0; i < formats_num_; i++)
+ {
+ if((format_etc_[i].tymed & pFormatEtc->tymed) &&
+ (format_etc_[i].cfFormat == pFormatEtc->cfFormat) &&
+ (format_etc_[i].dwAspect == pFormatEtc->dwAspect))
+ {
+ // return index of stored format
+ return i;
+ }
+ }
+
+ // error, format not found
+ return -1;
+}
+
+void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count)
+{
+ IDataObject *object = new DataObject((FORMATETC *)fmtetc, (STGMEDIUM *)stgmeds, (UINT)count);
+ assert(object != NULL);
+ return object;
+}
+
+void _ecore_win32_dnd_data_object_free(void *data_object)
+{
+ if (!data_object)
+ return;
+
+ IDataObject *object = (IDataObject *)data_object;
+ object->Release();
+}
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_data_object.h b/src/lib/ecore_win32/ecore_win32_dnd_data_object.h
new file mode 100644
index 0000000000..3d289cf7f5
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_data_object.h
@@ -0,0 +1,49 @@
+#ifndef __ECORE_WIN32_DND_DATA_OBJECT_H__
+#define __ECORE_WIN32_DND_DATA_OBJECT_H__
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <objbase.h>
+
+
+class DataObject : public IDataObject
+{
+ private:
+
+ LONG ref_count_;
+ int formats_num_;
+ FORMATETC *format_etc_;
+ STGMEDIUM *stg_medium_;
+
+ private: // internal helper function
+
+ int lookup_format_etc(FORMATETC *format_etc);
+
+ public: // structors
+
+ DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count);
+ ~DataObject();
+
+ public: // IUnknown
+
+ HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject);
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ public: // IDataObject
+
+ HRESULT __stdcall GetData(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
+ HRESULT __stdcall GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
+ HRESULT __stdcall QueryGetData(FORMATETC *pFormatEtc);
+ HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut);
+ HRESULT __stdcall SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease);
+ HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
+ HRESULT __stdcall DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *);
+ HRESULT __stdcall DUnadvise(DWORD dwConnection);
+ HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppEnumAdvise);
+};
+
+
+#endif /* __ECORE_WIN32_DND_DATA_OBJECT_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp
new file mode 100644
index 0000000000..a3a8bb1865
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp
@@ -0,0 +1,92 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "ecore_win32_dnd_drop_source.h"
+
+#include "ecore_win32_private.h"
+
+// structors
+
+// reference count must ALWAYS start at 1
+DropSource::DropSource() : ref_count_(1)
+{ }
+
+
+// IUnknown
+
+HRESULT DropSource::QueryInterface(REFIID iid, void **ppvObject)
+{
+ // check to see what interface has been requested
+ if (iid == IID_IDropSource || iid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObject = this;
+ return S_OK;
+ }
+ *ppvObject = 0;
+ return E_NOINTERFACE;
+}
+
+ULONG DropSource::AddRef()
+{
+ return InterlockedIncrement(&ref_count_);
+}
+
+ULONG DropSource::Release()
+{
+ LONG count = InterlockedDecrement(&ref_count_);
+ if(count == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return count;
+}
+
+
+// IDropSource
+
+HRESULT DropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
+{
+ // if the Escape key has been pressed since the last call, cancel the drop
+ if(fEscapePressed == TRUE)
+ return DRAGDROP_S_CANCEL;
+
+ // if the LeftMouse button has been released, then do the drop!
+ if((grfKeyState & MK_LBUTTON) == 0)
+ return DRAGDROP_S_DROP;
+
+ // continue with the drag-drop
+ return S_OK;
+}
+
+HRESULT DropSource::GiveFeedback(DWORD dwEffect EINA_UNUSED)
+{
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+
+// ecore_win32 private functions
+
+void *_ecore_win32_dnd_drop_source_new()
+{
+ IDropSource *object = new DropSource();
+ assert(object != NULL);
+ return object;
+}
+
+void _ecore_win32_dnd_drop_source_free(void *drop_source)
+{
+ if (!drop_source)
+ return;
+
+ IDropSource *object = (IDropSource *)drop_source;
+ object->Release();
+}
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h
new file mode 100644
index 0000000000..9081f46a15
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h
@@ -0,0 +1,36 @@
+#ifndef __ECORE_WIN32_DND_DROP_SOURCE_H__
+#define __ECORE_WIN32_DND_DROP_SOURCE_H__
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <ole2.h>
+
+#include "Ecore_Win32.h"
+
+
+class DropSource : public IDropSource
+{
+ private:
+
+ LONG ref_count_;
+
+ public: // structors
+
+ DropSource();
+
+ public: // IUnknown
+
+ HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ public: // IDropSource
+
+ HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
+ HRESULT __stdcall GiveFeedback(DWORD dwEffect);
+};
+
+
+#endif /* __ECORE_WIN32_DND_DROP_SOURCE_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp
new file mode 100644
index 0000000000..2f2da1af65
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp
@@ -0,0 +1,232 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecore_win32_dnd_drop_target.h"
+
+#include "ecore_win32_private.h"
+
+
+// structors
+
+DropTarget::DropTarget(HWND window, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr)
+ : ref_count_(1)
+ , window_(window)
+ , allow_drop_(false)
+ , drop_callback_(callback)
+ ,drop_callback_ptr_(window_obj_ptr)
+{ }
+
+
+// IUnknown
+
+HRESULT DropTarget::QueryInterface(REFIID iid, void **ppvObject)
+{
+ // check to see what interface has been requested
+ if (iid == IID_IDropTarget || iid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObject = this;
+ return S_OK;
+ }
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+}
+
+ULONG DropTarget::AddRef()
+{
+ return InterlockedIncrement(&ref_count_);
+}
+
+ULONG DropTarget::Release()
+{
+ LONG count = InterlockedDecrement(&ref_count_);
+ if (count == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return count;
+}
+
+
+// IDropTarget
+
+HRESULT DropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ // does the dataobject contain data we want?
+ allow_drop_ = QueryDataObject(pDataObject) &&
+ (drop_callback_ == NULL ||
+ (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_ENTER, pt.x, pt.y, NULL, 0) != 0));
+
+ if (allow_drop_)
+ {
+ // get the dropeffect based on keyboard state
+ *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
+ SetFocus(window_);
+ //PositionCursor(_hwnd, pt);
+ }
+ else
+ *pdwEffect = DROPEFFECT_NONE;
+ return S_OK;
+}
+
+HRESULT DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
+{
+ allow_drop_ =
+ (drop_callback_ == NULL) ||
+ (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_OVER, pt.x, pt.y, NULL, 0) != 0);
+
+ if (allow_drop_)
+ {
+ *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
+ //PositionCursor(m_hWnd, pt);
+ }
+ else
+ {
+ *pdwEffect = DROPEFFECT_NONE;
+ }
+
+ return S_OK;
+}
+
+HRESULT DropTarget::DragLeave()
+{
+ POINT pt;
+
+ GetCursorPos(&pt);
+ if (drop_callback_ != NULL)
+ drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_LEAVE, pt.x, pt.y, NULL, 0);
+
+ return S_OK;
+}
+
+HRESULT DropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ if (allow_drop_)
+ {
+ // construct a FORMATETC object
+ FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM stgmed;
+
+ // See if the dataobject contains any TEXT stored as a HGLOBAL
+ if (pDataObject->QueryGetData(&fmtetc) == S_OK)
+ {
+ // Yippie! the data is there, so go get it!
+ if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
+ {
+ // we asked for the data as a HGLOBAL, so access it appropriately
+ PVOID data = GlobalLock(stgmed.hGlobal);
+ UINT size = GlobalSize(stgmed.hGlobal);
+
+ if (drop_callback_ != NULL)
+ {
+ drop_callback_(drop_callback_ptr_,
+ ECORE_WIN32_DND_EVENT_DROP,
+ pt.x, pt.y,
+ data, size);
+ }
+
+ GlobalUnlock(stgmed.hGlobal);
+
+ // release the data using the COM API
+ ReleaseStgMedium(&stgmed);
+ }
+ }
+ *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
+ }
+ else
+ {
+ *pdwEffect = DROPEFFECT_NONE;
+ }
+
+ return S_OK;
+}
+
+
+// internal helper function
+
+DWORD DropTarget::DropEffect(DWORD grfKeyState, POINTL pt EINA_UNUSED, DWORD dwAllowed)
+{
+ DWORD dwEffect = 0;
+
+ // 1. check "pt" -> do we allow a drop at the specified coordinates?
+
+ // 2. work out that the drop-effect should be based on grfKeyState
+ if (grfKeyState & MK_CONTROL)
+ {
+ dwEffect = dwAllowed & DROPEFFECT_COPY;
+ }
+ else if (grfKeyState & MK_SHIFT)
+ {
+ dwEffect = dwAllowed & DROPEFFECT_MOVE;
+ }
+
+ // 3. no key-modifiers were specified (or drop effect not allowed), so
+ // base the effect on those allowed by the dropsource
+ if (dwEffect == 0)
+ {
+ if (dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY;
+ if (dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE;
+ }
+
+ return dwEffect;
+}
+
+bool DropTarget::QueryDataObject(IDataObject *pDataObject)
+{
+ FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+
+ // does the data object support CF_TEXT using a HGLOBAL?
+ return pDataObject->QueryGetData(&fmtetc) == S_OK;
+}
+
+
+// ecore_win32 private functions
+
+void *_ecore_win32_dnd_register_drop_window(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr)
+{
+ DropTarget *pDropTarget = new DropTarget(hwnd, callback, ptr);
+
+ if (pDropTarget == NULL)
+ return NULL;
+
+ // acquire a strong lock
+ if (FAILED(CoLockObjectExternal(pDropTarget, TRUE, FALSE)))
+ {
+ delete pDropTarget;
+ return NULL;
+ }
+
+ // tell OLE that the window is a drop target
+ if (FAILED(RegisterDragDrop(hwnd, pDropTarget)))
+ {
+ delete pDropTarget;
+ return NULL;
+ }
+
+ return pDropTarget;
+}
+
+void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target)
+{
+ IDropTarget *pDropTarget = (IDropTarget *)drop_target;
+
+ if (drop_target == NULL)
+ return;
+
+ // remove drag+drop
+ RevokeDragDrop(hwnd);
+
+ // remove the strong lock
+ CoLockObjectExternal(pDropTarget, FALSE, TRUE);
+
+ // release our own reference
+ pDropTarget->Release();
+}
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h
new file mode 100644
index 0000000000..24c3de3e1a
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h
@@ -0,0 +1,47 @@
+#ifndef __ECORE_WIN32_DND_DROP_TARGET_H__
+#define __ECORE_WIN32_DND_DROP_TARGET_H__
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <ole2.h>
+
+#include "Ecore_Win32.h"
+
+
+class DropTarget : public IDropTarget
+{
+ private:
+
+ LONG ref_count_;
+ HWND window_;
+ bool allow_drop_;
+ Ecore_Win32_Dnd_DropTarget_Callback drop_callback_;
+ void *drop_callback_ptr_;
+
+ private: // internal helper function
+
+ DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed);
+ bool QueryDataObject(IDataObject *pDataObject);
+
+ public: // structors
+
+ DropTarget(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr);
+
+public: // IUnknown
+
+ HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ public: // IDropTarget
+
+ HRESULT __stdcall DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
+ HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
+ HRESULT __stdcall DragLeave();
+ HRESULT __stdcall Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
+};
+
+
+#endif /* __ECORE_WIN32_DND_DROP_TARGET_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp
new file mode 100644
index 0000000000..a3858bcdd8
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp
@@ -0,0 +1,157 @@
+
+#include <ole2.h>
+
+#include "ecore_win32_dnd_enumformatetc.h"
+
+
+// structors
+
+CEnumFormatEtc::CEnumFormatEtc(FORMATETC *format_etc, int formats_num)
+ : ref_count_(1)
+ , index_(0)
+ , formats_num_(formats_num)
+ , format_etc_(new FORMATETC[formats_num])
+{
+ // make a new copy of each FORMATETC structure
+ for (unsigned int i = 0; i < formats_num_; i++)
+ {
+ DeepCopyFormatEtc(&format_etc_[i], &format_etc[i]);
+ }
+}
+
+CEnumFormatEtc::~CEnumFormatEtc()
+{
+ if (format_etc_)
+ {
+ // first free any DVTARGETDEVICE structures
+ for (ULONG i = 0; i < formats_num_; i++)
+ {
+ if (format_etc_[i].ptd)
+ CoTaskMemFree(format_etc_[i].ptd);
+ }
+
+ // now free the main array
+ delete[] format_etc_;
+ }
+}
+
+// IUnknown
+
+ULONG __stdcall CEnumFormatEtc::AddRef(void)
+{
+ // increment object reference count
+ return InterlockedIncrement(&ref_count_);
+}
+
+ULONG __stdcall CEnumFormatEtc::Release(void)
+{
+ // decrement object reference count
+ LONG count = InterlockedDecrement(&ref_count_);
+
+ if (count == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return count;
+ }
+}
+
+HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
+{
+ // check to see what interface has been requested
+ if ((iid == IID_IEnumFORMATETC) || (iid == IID_IUnknown))
+ {
+ AddRef();
+ *ppvObject = this;
+ return S_OK;
+ }
+ else
+ {
+ *ppvObject = 0;
+ return E_NOINTERFACE;
+ }
+}
+
+// IEnumFormatEtc
+
+HRESULT CEnumFormatEtc::Reset(void)
+{
+ index_ = 0;
+ return S_OK;
+}
+
+HRESULT CEnumFormatEtc::Skip(ULONG celt)
+{
+ index_ += celt;
+ return (index_ <= formats_num_) ? S_OK : S_FALSE;
+}
+
+HRESULT CEnumFormatEtc::Clone(IEnumFORMATETC **ppEnumFormatEtc)
+{
+ HRESULT hResult;
+
+ // make a duplicate enumerator
+ hResult = CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
+
+ if (hResult == S_OK)
+ {
+ // manually set the index state
+ ((CEnumFormatEtc *)*ppEnumFormatEtc)->index_ = index_;
+ }
+
+ return hResult;
+}
+
+HRESULT CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
+{
+ ULONG copied = 0;
+
+ // validate arguments
+ if ((celt == 0) || (pFormatEtc == 0))
+ return E_INVALIDARG;
+
+ // copy the FORMATETC structures into the caller's buffer
+ while (index_ < formats_num_ && copied < celt)
+ {
+ DeepCopyFormatEtc(&pFormatEtc[copied], &format_etc_[index_]);
+ copied++;
+ index_++;
+ }
+
+ // store result
+ if (pceltFetched != 0)
+ *pceltFetched = copied;
+
+ // did we copy all that was requested?
+ return (copied == celt) ? S_OK : S_FALSE;
+}
+
+// external functions
+
+void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
+{
+ // copy the source FORMATETC into dest
+ *dest = *source;
+
+ if (source->ptd)
+ {
+ // allocate memory for the DVTARGETDEVICE if necessary
+ dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
+
+ // copy the contents of the source DVTARGETDEVICE into dest->ptd
+ *(dest->ptd) = *(source->ptd);
+ }
+}
+
+HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
+{
+ if((cfmt == 0) || (afmt == 0) || (ppEnumFormatEtc == 0))
+ return E_INVALIDARG;
+
+ *ppEnumFormatEtc = new CEnumFormatEtc(afmt, cfmt);
+
+ return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
+}
diff --git a/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h
new file mode 100644
index 0000000000..9f17f5684e
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h
@@ -0,0 +1,50 @@
+#ifndef __ECORE_WIN32_DND_ENUMFORMATETC_H__
+#define __ECORE_WIN32_DND_ENUMFORMATETC_H__
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <objbase.h>
+
+
+class CEnumFormatEtc : public IEnumFORMATETC
+{
+ private:
+
+ LONG ref_count_; // Reference count for this COM interface
+ ULONG index_; // current enumerator index
+ ULONG formats_num_; // number of FORMATETC members
+ FORMATETC *format_etc_; // array of FORMATETC objects
+
+ public: // structors
+
+ CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats);
+
+ ~CEnumFormatEtc();
+
+ public: // IUnknown
+
+ HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
+
+ ULONG __stdcall AddRef (void);
+
+ ULONG __stdcall Release (void);
+
+ public: // IEnumFormatEtc
+
+ HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
+
+ HRESULT __stdcall Skip (ULONG celt);
+
+ HRESULT __stdcall Reset (void);
+
+ HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc);
+};
+
+void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source);
+
+HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc);
+
+
+#endif /* __ECORE_WIN32_DND_ENUMFORMATETC_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32_event.c b/src/lib/ecore_win32/ecore_win32_event.c
new file mode 100644
index 0000000000..fc285995fc
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_event.c
@@ -0,0 +1,1307 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h> /* for printf */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <windowsx.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+
+typedef enum
+{
+ ECORE_WIN32_KEY_MASK_LSHIFT = 1 << 0,
+ ECORE_WIN32_KEY_MASK_RSHIFT = 1 << 1,
+ ECORE_WIN32_KEY_MASK_LCONTROL = 1 << 2,
+ ECORE_WIN32_KEY_MASK_RCONTROL = 1 << 3,
+ ECORE_WIN32_KEY_MASK_LMENU = 1 << 4,
+ ECORE_WIN32_KEY_MASK_RMENU = 1 << 5
+} Ecore_Win32_Key_Mask;
+
+/***** Private declarations *****/
+
+
+static Ecore_Win32_Window *_ecore_win32_mouse_down_last_window = NULL;
+static Ecore_Win32_Window *_ecore_win32_mouse_down_last_last_window = NULL;
+static long _ecore_win32_mouse_down_last_time = 0 ;
+static long _ecore_win32_mouse_down_last_last_time = 0 ;
+static int _ecore_win32_mouse_down_did_triple = 0;
+static int _ecore_win32_mouse_up_count = 0;
+static Ecore_Win32_Key_Mask _ecore_win32_key_mask = 0;
+
+static void _ecore_win32_event_free_key_down(void *data,
+ void *ev);
+
+static void _ecore_win32_event_free_key_up(void *data,
+ void *ev);
+
+static int _ecore_win32_event_keystroke_get(Ecore_Win32_Callback_Data *msg,
+ Eina_Bool is_down,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose,
+ unsigned int *modifiers);
+
+static int _ecore_win32_event_char_get(int key,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose,
+ unsigned int *modifiers);
+
+
+/***** Global functions definitions *****/
+
+void
+_ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg,
+ int is_keystroke)
+{
+ Ecore_Event_Key *e;
+
+ INF("key pressed");
+
+ e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key));
+ if (!e) return;
+
+ if (is_keystroke)
+ {
+ if (!_ecore_win32_event_keystroke_get(msg,
+ EINA_TRUE,
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string,
+ &e->modifiers))
+ {
+ free(e);
+ return;
+ }
+ }
+ else
+ {
+ if (!_ecore_win32_event_char_get(LOWORD(msg->window_param),
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string,
+ &e->modifiers))
+ {
+ free(e);
+ return;
+ }
+ }
+
+ e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+ e->event_window = e->window;
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_win32_event_free_key_down, NULL);
+}
+
+void
+_ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Event_Key *e;
+
+ INF("key released");
+
+ e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key));
+ if (!e) return;
+
+ if (!_ecore_win32_event_keystroke_get(msg,
+ EINA_FALSE,
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string,
+ &e->modifiers))
+ {
+ if (msg->discard_ctrl ||
+ !_ecore_win32_event_char_get(LOWORD(msg->window_param),
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string,
+ &e->modifiers))
+ {
+ free(e);
+ return;
+ }
+ }
+
+ e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+ e->event_window = e->window;
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_win32_event_free_key_up, NULL);
+}
+
+void
+_ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg,
+ int button)
+{
+ Ecore_Win32_Window *window;
+
+ INF("mouse button pressed");
+
+ window = (Ecore_Win32_Window *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ if (button > 3)
+ {
+ Ecore_Event_Mouse_Wheel *e;
+
+ e = (Ecore_Event_Mouse_Wheel *)calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->direction = 0;
+ /* wheel delta is positive or negative, never 0 */
+ e->z = GET_WHEEL_DELTA_WPARAM(msg->window_param) > 0 ? -1 : 1;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL);
+ }
+ else
+ {
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Event_Mouse_Button *e;
+
+ if (_ecore_win32_mouse_down_did_triple)
+ {
+ _ecore_win32_mouse_down_last_window = NULL;
+ _ecore_win32_mouse_down_last_last_window = NULL;
+ _ecore_win32_mouse_down_last_time = 0;
+ _ecore_win32_mouse_down_last_last_time = 0;
+ }
+
+ e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->buttons = button;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ if (((e->timestamp - _ecore_win32_mouse_down_last_time) <= (unsigned long)(1000 * _ecore_win32_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window))
+ e->double_click = 1;
+
+ if (((e->timestamp - _ecore_win32_mouse_down_last_last_time) <= (unsigned long)(2 * 1000 * _ecore_win32_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_last_window))
+ {
+ e->triple_click = 1;
+ _ecore_win32_mouse_down_did_triple = 1;
+ }
+ else
+ _ecore_win32_mouse_down_did_triple = 0;
+
+ if (!e->double_click && !e->triple_click)
+ _ecore_win32_mouse_up_count = 0;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ if (!_ecore_win32_mouse_down_did_triple)
+ {
+ _ecore_win32_mouse_down_last_last_window = _ecore_win32_mouse_down_last_window;
+ _ecore_win32_mouse_down_last_window = (Ecore_Win32_Window *)e->window;
+ _ecore_win32_mouse_down_last_last_time = _ecore_win32_mouse_down_last_time;
+ _ecore_win32_mouse_down_last_time = e->timestamp;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL);
+ }
+ }
+}
+
+void
+_ecore_win32_event_handle_button_release(Ecore_Win32_Callback_Data *msg,
+ int button)
+{
+ Ecore_Win32_Window *window;
+
+ INF("mouse button released");
+
+ window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Event_Mouse_Button *e;
+
+ e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->buttons = button;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_mouse_up_count++;
+
+ if ((_ecore_win32_mouse_up_count >= 2) &&
+ ((e->timestamp - _ecore_win32_mouse_down_last_time) <= (unsigned long)(1000 * _ecore_win32_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window))
+ e->double_click = 1;
+
+ if ((_ecore_win32_mouse_up_count >= 3) &&
+ ((e->timestamp - _ecore_win32_mouse_down_last_last_time) <= (unsigned long)(2 * 1000 * _ecore_win32_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window) &&
+ (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_last_window))
+ e->triple_click = 1;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_win32_event_handle_motion_notify(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Event_Mouse_Move *e;
+
+ INF("mouse moved");
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->event_window = e->window;
+ e->x = GET_X_LPARAM(msg->data_param);
+ e->y = GET_Y_LPARAM(msg->data_param);
+ e->timestamp = msg->timestamp;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg)
+{
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ INF("mouse in");
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->event_window = e->window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Win32_Event_Mouse_In *e;
+
+ e = (Ecore_Win32_Event_Mouse_In *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_In));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->timestamp ;
+
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_WIN32_EVENT_MOUSE_IN, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg)
+{
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ INF("mouse out");
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->event_window = e->window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+ _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Win32_Event_Mouse_Out *e;
+
+ e = (Ecore_Win32_Event_Mouse_Out *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Out));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->timestamp;
+
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_WIN32_EVENT_MOUSE_OUT, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_win32_event_handle_focus_in(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Focus_In *e;
+
+ INF("focus in");
+
+ e = (Ecore_Win32_Event_Window_Focus_In *)calloc(1, sizeof(Ecore_Win32_Event_Window_Focus_In));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_focus_out(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Focus_Out *e;
+
+ INF("focus out");
+
+ e = (Ecore_Win32_Event_Window_Focus_Out *)calloc(1, sizeof(Ecore_Win32_Event_Window_Focus_Out));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+ _ecore_win32_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_expose(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Damage *e;
+
+ INF("window expose");
+
+ e = (Ecore_Win32_Event_Window_Damage *)calloc(1, sizeof(Ecore_Win32_Event_Window_Damage));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->x = msg->update.left;
+ e->y = msg->update.top;
+ e->width = msg->update.right - msg->update.left;
+ e->height = msg->update.bottom - msg->update.top;
+
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_create_notify(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Create *e;
+
+ INF("window create notify");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Create));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CREATE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_destroy_notify(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Destroy *e;
+
+ INF("window destroy notify");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Destroy));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+ if (e->window == _ecore_win32_event_last_window) _ecore_win32_event_last_window = NULL;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DESTROY, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_map_notify(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Show *e;
+
+ INF("window map notify");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Show));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_SHOW, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_unmap_notify(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Hide *e;
+
+ INF("window unmap notify");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Hide));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_HIDE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg)
+{
+ WINDOWINFO wi;
+ Ecore_Win32_Event_Window_Configure *e;
+ WINDOWPOS *window_pos;
+
+ INF("window configure notify");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Configure));
+ if (!e) return;
+
+ window_pos = (WINDOWPOS *)msg->data_param;
+ wi.cbSize = sizeof(WINDOWINFO);
+ if (!GetWindowInfo(window_pos->hwnd, &wi))
+ {
+ free(e);
+ return;
+ }
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->abovewin = (void *)GetWindowLongPtr(window_pos->hwndInsertAfter, GWLP_USERDATA);
+ e->x = wi.rcClient.left;
+ e->y = wi.rcClient.top;
+ e->width = wi.rcClient.right - wi.rcClient.left;
+ e->height = wi.rcClient.bottom - wi.rcClient.top;
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_resize(Ecore_Win32_Callback_Data *msg)
+{
+ RECT rect;
+ Ecore_Win32_Event_Window_Resize *e;
+
+ INF("window resize");
+
+ if (!GetClientRect(msg->window, &rect))
+ return;
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Resize));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->width = rect.right - rect.left;
+ e->height = rect.bottom - rect.top;
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_RESIZE, e, NULL, NULL);
+}
+
+void
+_ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg)
+{
+ Ecore_Win32_Event_Window_Delete_Request *e;
+
+ INF("window delete request");
+
+ e = calloc(1, sizeof(Ecore_Win32_Event_Window_Delete_Request));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+ e->timestamp = _ecore_win32_event_last_time;
+
+ ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL);
+}
+
+
+/***** Private functions definitions *****/
+
+static void
+_ecore_win32_event_free_key_down(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Event_Key *e;
+
+ e = ev;
+ if (e->keyname) free((char *)e->keyname);
+ if (e->key) free((char *)e->key);
+ if (e->string) free((char *)e->string);
+ free(e);
+}
+
+static void
+_ecore_win32_event_free_key_up(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Event_Key *e;
+
+ e = ev;
+ if (e->keyname) free((char *)e->keyname);
+ if (e->key) free((char *)e->key);
+ if (e->string) free((char *)e->string);
+ free(e);
+}
+
+static int
+_ecore_win32_event_keystroke_get(Ecore_Win32_Callback_Data *msg,
+ Eina_Bool is_down,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose,
+ unsigned int *modifiers)
+{
+ WCHAR buf[3];
+ char delete_string[2] = { 0x7f, 0 };
+ char *kn = NULL;
+ char *ks = NULL;
+ char *kc = NULL;
+ int key;
+ int is_extended;
+ int previous_key_state;
+
+ key = msg->window_param;
+ is_extended = msg->data_param & 0x01000000;
+ previous_key_state = msg->data_param & 0x40000000;
+
+ *keyname = NULL;
+ *keysymbol = NULL;
+ *keycompose = NULL;
+
+ switch (key)
+ {
+ /* Keystroke */
+ case VK_PRIOR:
+ if (is_extended)
+ {
+ kn = "Prior";
+ ks = "Prior";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Prior";
+ ks = "KP_9";
+ kc = "KP_Prior";
+ }
+ break;
+ case VK_NEXT:
+ if (is_extended)
+ {
+ kn = "Next";
+ ks = "Next";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Next";
+ ks = "KP_3";
+ kc = "KP_Next";
+ }
+ break;
+ case VK_END:
+ if (is_extended)
+ {
+ kn = "End";
+ ks = "End";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_End";
+ ks = "KP_1";
+ kc = "KP_End";
+ }
+ break;
+ case VK_HOME:
+ if (is_extended)
+ {
+ kn = "Home";
+ ks = "Home";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Home";
+ ks = "KP_7";
+ kc = "KP_Home";
+ }
+ break;
+ case VK_LEFT:
+ if (is_extended)
+ {
+ kn = "Left";
+ ks = "Left";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Left";
+ ks = "KP_4";
+ kc = "KP_Left";
+ }
+ break;
+ case VK_UP:
+ if (is_extended)
+ {
+ kn = "Up";
+ ks = "Up";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Up";
+ ks = "KP_8";
+ kc = "KP_Up";
+ }
+ break;
+ case VK_RIGHT:
+ if (is_extended)
+ {
+ kn = "Right";
+ ks = "Right";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Right";
+ ks = "KP_6";
+ kc = "KP_Right";
+ }
+ break;
+ case VK_DOWN:
+ if (is_extended)
+ {
+ kn = "Down";
+ ks = "Down";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Down";
+ ks = "KP_2";
+ kc = "KP_Down";
+ }
+ break;
+ case VK_INSERT:
+ if (is_extended)
+ {
+ kn = "Insert";
+ ks = "Insert";
+ kc = NULL;
+ }
+ else
+ {
+ kn = "KP_Insert";
+ ks = "KP_0";
+ kc = "KP_Insert";
+ }
+ break;
+ case VK_DELETE:
+ if (is_extended)
+ {
+ kn = "Delete";
+ ks = "Delete";
+ kc = delete_string;
+ }
+ else
+ {
+ kn = "KP_Delete";
+ ks = "KP_Decimal";
+ kc = "KP_Delete";
+ }
+ break;
+ case VK_SHIFT:
+ {
+ SHORT res;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LSHIFT);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LSHIFT;
+ kn = "Shift_L";
+ ks = "Shift_L";
+ kc = "";
+ }
+ res = GetKeyState(VK_RSHIFT);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RSHIFT;
+ kn = "Shift_R";
+ ks = "Shift_R";
+ kc = "";
+ }
+ *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT;
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LSHIFT);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LSHIFT))
+ {
+ kn = "Shift_L";
+ ks = "Shift_L";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LSHIFT;
+ }
+ res = GetKeyState(VK_RSHIFT);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RSHIFT))
+ {
+ kn = "Shift_R";
+ ks = "Shift_R";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RSHIFT;
+ }
+ *modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ }
+ break;
+ }
+ case VK_CONTROL:
+ {
+ SHORT res;
+
+ if (msg->discard_ctrl)
+ return 0;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LCONTROL);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LCONTROL;
+ kn = "Control_L";
+ ks = "Control_L";
+ kc = "";
+ break;
+ }
+ res = GetKeyState(VK_RCONTROL);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RCONTROL;
+ kn = "Control_R";
+ ks = "Control_R";
+ kc = "";
+ break;
+ }
+ *modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LCONTROL);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LCONTROL))
+ {
+ kn = "Control_L";
+ ks = "Control_L";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LCONTROL;
+ break;
+ }
+ res = GetKeyState(VK_RCONTROL);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RCONTROL))
+ {
+ kn = "Control_R";
+ ks = "Control_R";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RCONTROL;
+ break;
+ }
+ *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL;
+ }
+ break;
+ }
+ case VK_MENU:
+ {
+ SHORT res;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LMENU);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LMENU;
+ kn = "Alt_L";
+ ks = "Alt_L";
+ kc = "";
+ }
+ res = GetKeyState(VK_RMENU);
+ if (res & 0x8000)
+ {
+ _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RMENU;
+ kn = "Alt_R";
+ ks = "Alt_R";
+ kc = "";
+ }
+ *modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LMENU);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LMENU))
+ {
+ kn = "Alt_L";
+ ks = "Alt_L";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LMENU;
+ }
+ res = GetKeyState(VK_RMENU);
+ if (!(res & 0x8000) &&
+ (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RMENU))
+ {
+ kn = "Alt_R";
+ ks = "Alt_R";
+ kc = "";
+ _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RMENU;
+ }
+ *modifiers &= ~ECORE_EVENT_MODIFIER_ALT;
+ }
+ break;
+ }
+ case VK_LWIN:
+ {
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ kn = "Super_L";
+ ks = "Super_L";
+ kc = "";
+ *modifiers |= ECORE_EVENT_MODIFIER_WIN;
+ }
+ else /* is_up */
+ {
+ kn = "Super_L";
+ ks = "Super_L";
+ kc = "";
+ *modifiers &= ~ECORE_EVENT_MODIFIER_WIN;
+ }
+ break;
+ }
+ case VK_RWIN:
+ {
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ kn = "Super_R";
+ ks = "Super_R";
+ kc = "";
+ *modifiers |= ECORE_EVENT_MODIFIER_WIN;
+ }
+ else /* is_up */
+ {
+ kn = "Super_R";
+ ks = "Super_R";
+ kc = "";
+ *modifiers &= ~ECORE_EVENT_MODIFIER_WIN;
+ }
+ break;
+ }
+ case VK_F1:
+ kn = "F1";
+ ks = "F1";
+ kc = "";
+ break;
+ case VK_F2:
+ kn = "F2";
+ ks = "F2";
+ kc = "";
+ break;
+ case VK_F3:
+ kn = "F3";
+ ks = "F3";
+ kc = "";
+ break;
+ case VK_F4:
+ kn = "F4";
+ ks = "F4";
+ kc = "";
+ break;
+ case VK_F5:
+ kn = "F5";
+ ks = "F5";
+ kc = "";
+ break;
+ case VK_F6:
+ kn = "F6";
+ ks = "F6";
+ kc = "";
+ break;
+ case VK_F7:
+ kn = "F7";
+ ks = "F7";
+ kc = "";
+ break;
+ case VK_F8:
+ kn = "F8";
+ ks = "F8";
+ kc = "";
+ break;
+ case VK_F9:
+ kn = "F9";
+ ks = "F9";
+ kc = "";
+ break;
+ case VK_F10:
+ kn = "F10";
+ ks = "F10";
+ kc = "";
+ break;
+ case VK_F11:
+ kn = "F11";
+ ks = "F11";
+ kc = "";
+ break;
+ case VK_F12:
+ kn = "F12";
+ ks = "F12";
+ kc = "";
+ break;
+ case VK_F13:
+ kn = "F13";
+ ks = "F13";
+ kc = "";
+ break;
+ case VK_F14:
+ kn = "F14";
+ ks = "F14";
+ kc = "";
+ break;
+ case VK_F15:
+ kn = "F15";
+ ks = "F15";
+ kc = "";
+ break;
+ case VK_F16:
+ kn = "F16";
+ ks = "F16";
+ kc = "";
+ break;
+ case VK_F17:
+ kn = "F17";
+ ks = "F17";
+ kc = "";
+ break;
+ case VK_F18:
+ kn = "F18";
+ ks = "F18";
+ kc = "";
+ break;
+ case VK_F19:
+ kn = "F19";
+ ks = "F19";
+ kc = "";
+ break;
+ case VK_F20:
+ kn = "F20";
+ ks = "F20";
+ kc = "";
+ break;
+ case VK_F21:
+ kn = "F21";
+ ks = "F21";
+ kc = "";
+ break;
+ case VK_F22:
+ kn = "F22";
+ ks = "F22";
+ kc = "";
+ break;
+ case VK_F23:
+ kn = "F23";
+ ks = "F23";
+ kc = "";
+ break;
+ case VK_F24:
+ kn = "F24";
+ ks = "F24";
+ kc = "";
+ break;
+ default:
+ {
+ /* other non keystroke characters */
+ BYTE kbd_state[256];
+ int res;
+
+ if (is_down)
+ return 0;
+
+ if (!GetKeyboardState(kbd_state))
+ return 0;
+
+ res = ToUnicode(msg->window_param,
+ MapVirtualKey(msg->window_param, 2),
+ kbd_state, buf, 3, 0);
+ if (res == 1)
+ {
+ /* FIXME: might be troublesome for non european languages */
+ /* in that case, UNICODE should be used, I guess */
+ buf[1] = '\0';
+ kn = (char *)buf;
+ ks = (char *)buf;
+ kc = (char *)buf;
+
+ res = GetAsyncKeyState(VK_SHIFT);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT;
+
+ res = GetKeyState(VK_CONTROL);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL;
+
+ res = GetKeyState(VK_MENU);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_ALT;
+
+ break;
+ }
+ return 0;
+ }
+ }
+
+ *keyname = strdup(kn);
+ if (!*keyname) return 0;
+ *keysymbol = strdup(ks);
+ if (!*keysymbol)
+ {
+ free(*keyname);
+ *keyname = NULL;
+ return 0;
+ }
+ if (!kc)
+ *keycompose = NULL;
+ else
+ {
+ *keycompose = strdup(kc);
+ if (!*keycompose)
+ {
+ free(*keyname);
+ free(*keysymbol);
+ *keyname = NULL;
+ *keysymbol = NULL;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+_ecore_win32_event_char_get(int key,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose,
+ unsigned int *modifiers)
+{
+ char *kn = NULL;
+ char *ks = NULL;
+ char *kc = NULL;
+ char buf[2];
+ SHORT res;
+
+ *keyname = NULL;
+ *keysymbol = NULL;
+ *keycompose = NULL;
+
+ /* check control charaters such as ^a(key:1), ^z(key:26) */
+ if ((key > 0) && (key < 27) &&
+ ((GetKeyState(VK_CONTROL) & 0x8000) ||
+ (GetKeyState(VK_CONTROL) & 0x8000))) key += 96;
+
+ switch (key)
+ {
+ case VK_PROCESSKEY:
+ break;
+ case VK_BACK:
+ kn = "BackSpace";
+ ks = "BackSpace";
+ kc = "\b";
+ break;
+ case VK_TAB:
+ kn = "Tab";
+ ks = "Tab";
+ kc = "\t";
+ break;
+ case 0x0a:
+ /* Line feed (Shift + Enter) */
+ kn = "LineFeed";
+ ks = "LineFeed";
+ kc = "LineFeed";
+ break;
+ case VK_RETURN:
+ kn = "Return";
+ ks = "Return";
+ kc = "\n";
+ break;
+ case VK_ESCAPE:
+ kn = "Escape";
+ ks = "Escape";
+ kc = "\e";
+ break;
+ case VK_SPACE:
+ kn = "space";
+ ks = "space";
+ kc = " ";
+ break;
+ default:
+ /* displayable characters */
+ buf[0] = key;
+ buf[1] = '\0';
+ kn = buf;
+ ks = buf;
+ kc = buf;
+ break;
+ }
+ *keyname = strdup(kn);
+ if (!*keyname) return 0;
+ *keysymbol = strdup(ks);
+ if (!*keysymbol)
+ {
+ free(*keyname);
+ *keyname = NULL;
+ return 0;
+ }
+ *keycompose = strdup(kc);
+ if (!*keycompose)
+ {
+ free(*keyname);
+ free(*keysymbol);
+ *keyname = NULL;
+ *keysymbol = NULL;
+ return 0;
+ }
+
+ res = GetAsyncKeyState(VK_SHIFT);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT;
+
+ res = GetKeyState(VK_CONTROL);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL;
+
+ res = GetKeyState(VK_MENU);
+ if (res & 0x8000)
+ *modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ else
+ *modifiers &= ~ECORE_EVENT_MODIFIER_ALT;
+
+ return 1;
+}
diff --git a/src/lib/ecore_win32/ecore_win32_private.h b/src/lib/ecore_win32/ecore_win32_private.h
new file mode 100644
index 0000000000..e3e44264cc
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_private.h
@@ -0,0 +1,170 @@
+#ifndef __ECORE_WIN32_PRIVATE_H__
+#define __ECORE_WIN32_PRIVATE_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MIN
+# undef MIN
+#endif
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#ifdef MAX
+# undef MAX
+#endif
+#define MAX(a,b) (((a) < (b)) ? (b) : (a))
+
+/* logging messages macros */
+extern int _ecore_win32_log_dom_global;
+
+#ifdef ECORE_WIN32_DEFAULT_LOG_COLOR
+# undef ECORE_WIN32_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_WIN32_DEFAULT_LOG_COLOR EINA_COLOR_LIGHTBLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_win32_log_dom_global , __VA_ARGS__)
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_win32_log_dom_global , __VA_ARGS__)
+
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_win32_log_dom_global , __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_win32_log_dom_global, __VA_ARGS__)
+
+#define ECORE_WIN32_WINDOW_CLASS "Ecore_Win32_Window_Class"
+
+typedef struct _Ecore_Win32_Callback_Data Ecore_Win32_Callback_Data;
+
+struct _Ecore_Win32_Callback_Data
+{
+ RECT update;
+ HWND window;
+ unsigned int message;
+ WPARAM window_param;
+ LPARAM data_param;
+ unsigned long timestamp;
+ int x;
+ int y;
+ Eina_Bool discard_ctrl;
+};
+
+struct _Ecore_Win32_Window
+{
+ HWND window;
+
+ DWORD style; /* used to go fullscreen to normal */
+ RECT rect; /* used to go fullscreen to normal */
+
+ unsigned int min_width;
+ unsigned int min_height;
+ unsigned int max_width;
+ unsigned int max_height;
+ int base_width;
+ int base_height;
+ unsigned int step_width;
+ unsigned int step_height;
+
+ struct {
+ unsigned int iconified : 1;
+ unsigned int modal : 1;
+ unsigned int sticky : 1;
+ unsigned int maximized_vert : 1;
+ unsigned int maximized_horz : 1;
+ unsigned int shaded : 1;
+ unsigned int hidden : 1;
+ unsigned int fullscreen : 1;
+ unsigned int above : 1;
+ unsigned int below : 1;
+ unsigned int demands_attention : 1;
+ } state;
+
+ struct {
+ unsigned int desktop : 1;
+ unsigned int dock : 1;
+ unsigned int toolbar : 1;
+ unsigned int menu : 1;
+ unsigned int utility : 1;
+ unsigned int splash : 1;
+ unsigned int dialog : 1;
+ unsigned int normal : 1;
+ } type;
+
+ unsigned int pointer_is_in : 1;
+ unsigned int borderless : 1;
+ unsigned int iconified : 1;
+ unsigned int fullscreen : 1;
+
+ struct {
+ unsigned short width;
+ unsigned short height;
+ unsigned char *mask;
+ unsigned int enabled : 1;
+ unsigned int layered : 1;
+ } shape;
+
+ struct {
+ DWORD type;
+ int x;
+ int y;
+ int w;
+ int h;
+ int px;
+ int py;
+ unsigned int dragging : 1;
+ } drag;
+
+ void *dnd_drop_target;
+};
+
+
+extern HINSTANCE _ecore_win32_instance;
+extern double _ecore_win32_double_click_time;
+extern unsigned long _ecore_win32_event_last_time;
+extern Ecore_Win32_Window *_ecore_win32_event_last_window;
+
+
+void _ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg, int is_keystroke);
+void _ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg, int button);
+void _ecore_win32_event_handle_button_release(Ecore_Win32_Callback_Data *msg, int button);
+void _ecore_win32_event_handle_motion_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_focus_in(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_focus_out(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_expose(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_create_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_destroy_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_map_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_unmap_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_resize(Ecore_Win32_Callback_Data *msg);
+void _ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg);
+
+void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count);
+void _ecore_win32_dnd_data_object_free(void *data_object);
+void *_ecore_win32_dnd_drop_source_new();
+void _ecore_win32_dnd_drop_source_free(void *drop_source);
+void *_ecore_win32_dnd_register_drop_window(HWND hwnd,
+ Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr);
+void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ECORE_WIN32_PRIVATE_H__ */
diff --git a/src/lib/ecore_win32/ecore_win32_window.c b/src/lib/ecore_win32/ecore_win32_window.c
new file mode 100644
index 0000000000..36f8a86047
--- /dev/null
+++ b/src/lib/ecore_win32/ecore_win32_window.c
@@ -0,0 +1,1418 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h> /* for printf */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Eina.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+
+typedef enum _Ecore_Win32_Window_Z_Order Ecore_Win32_Window_Z_Order;
+enum _Ecore_Win32_Window_Z_Order
+{
+ ECORE_WIN32_WINDOW_Z_ORDER_BOTTOM,
+ ECORE_WIN32_WINDOW_Z_ORDER_NOTOPMOST,
+ ECORE_WIN32_WINDOW_Z_ORDER_TOP,
+ ECORE_WIN32_WINDOW_Z_ORDER_TOPMOST
+};
+
+static Ecore_Win32_Window *
+ecore_win32_window_internal_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ DWORD style)
+{
+ RECT rect;
+ Ecore_Win32_Window *w;
+ int minimal_width;
+ int minimal_height;
+
+ w = (Ecore_Win32_Window *)calloc(1, sizeof(Ecore_Win32_Window));
+ if (!w)
+ {
+ ERR("malloc() failed");
+ return NULL;
+ }
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+ if (!AdjustWindowRectEx(&rect, style, FALSE, 0))
+ {
+ ERR("AdjustWindowRect() failed");
+ free(w);
+ return NULL;
+ }
+
+ minimal_width = GetSystemMetrics(SM_CXMIN);
+ minimal_height = GetSystemMetrics(SM_CYMIN);
+/* if (((rect.right - rect.left) < minimal_width) || */
+/* ((rect.bottom - rect.top) < minimal_height)) */
+/* { */
+/* fprintf (stderr, "[Ecore] [Win32] ERROR !!\n"); */
+/* fprintf (stderr, " Wrong size %ld\n", rect.right - rect.left); */
+/* free(w); */
+/* return NULL; */
+/* } */
+ if ((rect.right - rect.left) < minimal_width)
+ {
+ rect.right = rect.left + minimal_width;
+ }
+
+ w->window = CreateWindowEx(0,
+ ECORE_WIN32_WINDOW_CLASS, "",
+ style,
+ x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ parent ? parent->window : NULL,
+ NULL, _ecore_win32_instance, NULL);
+ if (!w->window)
+ {
+ ERR("CreateWindowEx() failed");
+ free(w);
+ return NULL;
+ }
+
+ SetLastError(0);
+ if (!SetWindowLongPtr(w->window, GWLP_USERDATA, (LONG_PTR)w) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ DestroyWindow(w->window);
+ free(w);
+ return NULL;
+ }
+
+ w->min_width = 0;
+ w->min_height = 0;
+ w->max_width = 32767;
+ w->max_height = 32767;
+ w->base_width = -1;
+ w->base_height = -1;
+ w->step_width = 1;
+ w->step_height = 1;
+
+ w->state.iconified = 0;
+ w->state.modal = 0;
+ w->state.sticky = 0;
+ w->state.maximized_vert = 0;
+ w->state.maximized_horz = 0;
+ w->state.shaded = 0;
+ w->state.hidden = 0;
+ w->state.fullscreen = 0;
+ w->state.above = 0;
+ w->state.below = 0;
+ w->state.demands_attention = 0;
+
+ w->type.desktop = 0;
+ w->type.dock = 0;
+ w->type.toolbar = 0;
+ w->type.menu = 0;
+ w->type.utility = 0;
+ w->type.splash = 0;
+ w->type.dialog = 0;
+ w->type.normal = 0;
+
+ w->pointer_is_in = 0;
+ w->borderless = 0;
+ w->iconified = 0;
+ w->fullscreen = 0;
+
+ return w;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_Win32_Group Ecore_Win32 library
+ *
+ * @{
+ */
+
+/**
+ * @brief Creates a new window.
+ *
+ * @param parent The parent window.
+ * @param x The x coordinate of the top-left corner of the window.
+ * @param y The y coordinate of the top-left corner of the window.
+ * @param width The width of the window.
+ * @param height The height of hte window.
+ * @return A newly allocated window.
+ *
+ * This function creates a new window which parent is @p parent. @p width and
+ * @p height are the size of the window content (the client part),
+ * without the border and title bar. @p x and @p y are the system
+ * coordinates of the top left cerner of the window (that is, of the
+ * title bar). This function returns a newly created window on
+ * success, and @c NULL on failure.
+ */
+EAPI Ecore_Win32_Window *
+ecore_win32_window_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ INF("creating window with border");
+
+ return ecore_win32_window_internal_new(parent,
+ x, y,
+ width, height,
+ WS_OVERLAPPEDWINDOW | WS_SIZEBOX);
+}
+
+/**
+ * @brief Creates a new borderless window.
+ *
+ * @param parent The parent window.
+ * @param x The x coordinate of the top-left corner of the window.
+ * @param y The y coordinate of the top-left corner of the window.
+ * @param width The width of the window.
+ * @param height The height of hte window.
+ * @return A newly allocated window.
+ *
+ * This function is the same than ecore_win32_window_override_new()
+ * but the returned window is borderless.
+ */
+EAPI Ecore_Win32_Window *
+ecore_win32_window_override_new(Ecore_Win32_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ INF("creating window without border");
+
+ return ecore_win32_window_internal_new(parent,
+ x, y,
+ width, height,
+ WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME));
+}
+
+/**
+ * @brief Free the given window.
+ *
+ * @param window The window to free.
+ *
+ * This function frees @p window. If @p window is @c NULL, this
+ * function does nothing.
+ */
+EAPI void
+ecore_win32_window_free(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("destroying window");
+
+ if (window->shape.mask)
+ free(window->shape.mask);
+
+ DestroyWindow(window->window);
+ free(window);
+}
+
+/**
+ * @brief Return the window HANDLE associated to the given window.
+ *
+ * @param window The window to retrieve the HANDLE from.
+ *
+ * This function returns the window HANDLE associated to @p window. If
+ * @p window is @c NULL, this function returns @c NULL.
+ *
+ * @note The returned value is of type HWND.
+ */
+EAPI void *
+ecore_win32_window_hwnd_get(Ecore_Win32_Window *window)
+{
+ if (!window) return NULL;
+
+ return window->window;
+}
+
+/*
+void
+ecore_win32_window_configure(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_Z_Order order,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ HWND w;
+
+ switch (order)
+ {
+ case ECORE_WIN32_WINDOW_Z_ORDER_BOTTOM:
+ w = HWND_BOTTOM;
+ break;
+ case ECORE_WIN32_WINDOW_Z_ORDER_NOTOPMOST:
+ w = HWND_NOTOPMOST;
+ break;
+ case ECORE_WIN32_WINDOW_Z_ORDER_TOP:
+ w = HWND_TOP;
+ break;
+ case ECORE_WIN32_WINDOW_Z_ORDER_TOPMOST:
+ w = HWND_TOPMOST;
+ break;
+ default:
+ return;
+ }
+ SetWindowPos((Ecore_Win32_Window *)window->window, w, x, y, width, height, ???);
+}
+*/
+
+/**
+ * @brief Move the given window to a given position.
+ *
+ * @param window The window to move.
+ * @param x The x coordinate of the destination position.
+ * @param y The y coordinate of the destination position.
+ *
+ * This function move @p window to the new position of coordinates @p x
+ * and @p y. If @p window is @c NULL, or if it is fullscreen, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_move(Ecore_Win32_Window *window,
+ int x,
+ int y)
+{
+ RECT rect;
+
+ /* FIXME: on fullscreen, should not move it */
+ if (!window) return;
+
+ INF("moving window (%dx%d)", x, y);
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Resize the given window to a given size.
+ *
+ * @param window The window to resize.
+ * @param width The new width.
+ * @param height The new height.
+ *
+ * This function resize @p window to the new @p width and @p height.
+ * If @p window is @c NULL, or if it is fullscreen, or on error, this
+ * function does nothing.
+ */
+EAPI void
+ecore_win32_window_resize(Ecore_Win32_Window *window,
+ int width,
+ int height)
+{
+ RECT rect;
+ DWORD style;
+ int x;
+ int y;
+ int minimal_width;
+ int minimal_height;
+
+ /* FIXME: on fullscreen, should not resize it */
+ if (!window) return;
+
+ INF("resizing window (%dx%d)", width, height);
+
+ minimal_width = MAX(GetSystemMetrics(SM_CXMIN), (int)window->min_width);
+ minimal_height = MAX(GetSystemMetrics(SM_CYMIN), (int)window->min_height);
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+
+ x = rect.left;
+ y = rect.top;
+ rect.left = 0;
+ rect.top = 0;
+ if (width < minimal_width) width = minimal_width;
+ if (width > (int)window->max_width) width = window->max_width;
+ if (height < minimal_height) height = minimal_height;
+ if (height > (int)window->max_height) height = window->max_height;
+ rect.right = width;
+ rect.bottom = height;
+ if (!(style = GetWindowLong(window->window, GWL_STYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!AdjustWindowRect(&rect, style, FALSE))
+ {
+ ERR("AdjustWindowRect() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Move and resize the given window to a given position and size.
+ *
+ * @param window The window to move and resize.
+ * @param x The x coordinate of the destination position.
+ * @param y The x coordinate of the destination position.
+ * @param width The new width.
+ * @param height The new height.
+ *
+ * This function resize @p window to the new position of coordinates @p x
+ * and @p y and the new @p width and @p height. If @p window is @c NULL,
+ * or if it is fullscreen, or on error, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_move_resize(Ecore_Win32_Window *window,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ RECT rect;
+ DWORD style;
+ int minimal_width;
+ int minimal_height;
+
+ /* FIXME: on fullscreen, should not move/resize it */
+ if (!window) return;
+
+ INF("moving and resizing window (%dx%d %dx%d)", x, y, width, height);
+
+ minimal_width = MAX(GetSystemMetrics(SM_CXMIN), (int)window->min_width);
+ minimal_height = MAX(GetSystemMetrics(SM_CYMIN), (int)window->min_height);
+
+ rect.left = 0;
+ rect.top = 0;
+ if (width < minimal_width) width = minimal_width;
+ if (width > (int)window->max_width) width = window->max_width;
+ if (height < minimal_height) height = minimal_height;
+ if (height > (int)window->max_height) height = window->max_height;
+ rect.right = width;
+ rect.bottom = height;
+ if (!(style = GetWindowLong(window->window, GWL_STYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!AdjustWindowRect(&rect, style, FALSE))
+ {
+ ERR("AdjustWindowRect() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Get the geometry of the given window.
+ *
+ * @param window The window to retrieve the geometry from.
+ * @param x The x coordinate of the position.
+ * @param y The x coordinate of the position.
+ * @param width The width.
+ * @param height The height.
+ *
+ * This function retrieves the position and size of @p window. @p x,
+ * @p y, @p width and @p height can be buffers that will be filled with
+ * the corresponding values. If one of them is @c NULL, nothing will
+ * be done for that parameter. If @p window is @c NULL, and if the
+ * buffers are not @c NULL, they will be filled with respectively 0,
+ * 0, the size of the screen and the height of the screen.
+ */
+EAPI void
+ecore_win32_window_geometry_get(Ecore_Win32_Window *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ RECT rect;
+ int w;
+ int h;
+
+ INF("getting window geometry");
+
+ if (!window)
+ {
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = GetSystemMetrics(SM_CXSCREEN);
+ if (height) *height = GetSystemMetrics(SM_CYSCREEN);
+
+ return;
+ }
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = 0;
+ if (height) *height = 0;
+
+ return;
+ }
+
+ w = rect.right - rect.left;
+ h = rect.bottom - rect.top;
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = 0;
+ if (height) *height = 0;
+
+ return;
+ }
+
+ if (x) *x = rect.left;
+ if (y) *y = rect.top;
+ if (width) *width = w;
+ if (height) *height = h;
+}
+
+/**
+ * @brief Get the size of the given window.
+ *
+ * @param window The window to retrieve the size from.
+ * @param width The width.
+ * @param height The height.
+ *
+ * This function retrieves the size of @p window. @p width and
+ * @p height can be buffers that will be filled with the corresponding
+ * values. If one of them is @c NULL, nothing will be done for that
+ * parameter. If @p window is @c NULL, and if the buffers are not
+ * @c NULL, they will be filled with respectively the size of the screen
+ * and the height of the screen.
+ */
+EAPI void
+ecore_win32_window_size_get(Ecore_Win32_Window *window,
+ int *width,
+ int *height)
+{
+ RECT rect;
+
+ INF("getting window size");
+
+ if (!window)
+ {
+ if (width) *width = GetSystemMetrics(SM_CXSCREEN);
+ if (height) *height = GetSystemMetrics(SM_CYSCREEN);
+
+ return;
+ }
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+
+ if (width) *width = 0;
+ if (height) *height = 0;
+ }
+
+ if (width) *width = rect.right - rect.left;
+ if (height) *height = rect.bottom - rect.top;
+}
+
+/**
+ * @brief Set the minimum size of the given window.
+ *
+ * @param window The window.
+ * @param min_width The minimal width.
+ * @param min_height The minimal height.
+ *
+ * This function sets the minimum size of @p window to @p min_width
+ * and *p min_height. If @p window is @c NULL, this functions does
+ * nothing.
+ */
+EAPI void
+ecore_win32_window_size_min_set(Ecore_Win32_Window *window,
+ unsigned int min_width,
+ unsigned int min_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_min_set : %p %d %d\n", window, min_width, min_height);
+ window->min_width = min_width;
+ window->min_height = min_height;
+}
+
+/**
+ * @brief Get the minimum size of the given window.
+ *
+ * @param window The window.
+ * @param min_width The minimal width.
+ * @param min_height The minimal height.
+ *
+ * This function fills the minimum size of @p window in the buffers
+ * @p min_width and *p min_height. They both can be @c NULL. If
+ * @p window is @c NULL, this functions does nothing.
+ */
+EAPI void
+ecore_win32_window_size_min_get(Ecore_Win32_Window *window,
+ unsigned int *min_width,
+ unsigned int *min_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_min_get : %p %d %d\n", window, window->min_width, window->min_height);
+ if (min_width) *min_width = window->min_width;
+ if (min_height) *min_height = window->min_height;
+}
+
+/**
+ * @brief Set the maximum size of the given window.
+ *
+ * @param window The window.
+ * @param max_width The maximal width.
+ * @param max_height The maximal height.
+ *
+ * This function sets the maximum size of @p window to @p max_width
+ * and *p max_height. If @p window is @c NULL, this functions does
+ * nothing.
+ */
+EAPI void
+ecore_win32_window_size_max_set(Ecore_Win32_Window *window,
+ unsigned int max_width,
+ unsigned int max_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_max_set : %p %d %d\n", window, max_width, max_height);
+ window->max_width = max_width;
+ window->max_height = max_height;
+}
+
+/**
+ * @brief Get the maximum size of the given window.
+ *
+ * @param window The window.
+ * @param max_width The maximal width.
+ * @param max_height The maximal height.
+ *
+ * This function fills the maximum size of @p window in the buffers
+ * @p max_width and *p max_height. They both can be @c NULL. If
+ * @p window is @c NULL, this functions does nothing.
+ */
+EAPI void
+ecore_win32_window_size_max_get(Ecore_Win32_Window *window,
+ unsigned int *max_width,
+ unsigned int *max_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_max_get : %p %d %d\n", window, window->max_width, window->max_height);
+ if (max_width) *max_width = window->max_width;
+ if (max_height) *max_height = window->max_height;
+}
+
+/**
+ * @brief Set the base size of the given window.
+ *
+ * @param window The window.
+ * @param base_width The base width.
+ * @param base_height The base height.
+ *
+ * This function sets the base size of @p window to @p base_width
+ * and *p base_height. If @p window is @c NULL, this functions does
+ * nothing.
+ */
+EAPI void
+ecore_win32_window_size_base_set(Ecore_Win32_Window *window,
+ unsigned int base_width,
+ unsigned int base_height)
+{
+ printf ("ecore_win32_window_size_base_set : %p %d %d\n", window, base_width, base_height);
+ if (!window) return;
+
+ window->base_width = base_width;
+ window->base_height = base_height;
+}
+
+/**
+ * @brief Get the base size of the given window.
+ *
+ * @param window The window.
+ * @param base_width The base width.
+ * @param base_height The bas height.
+ *
+ * This function fills the base size of @p window in the buffers
+ * @p base_width and *p base_height. They both can be @c NULL. If
+ * @p window is @c NULL, this functions does nothing.
+ */
+EAPI void
+ecore_win32_window_size_base_get(Ecore_Win32_Window *window,
+ unsigned int *base_width,
+ unsigned int *base_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_base_get : %p %d %d\n", window, window->base_width, window->base_height);
+ if (base_width) *base_width = window->base_width;
+ if (base_height) *base_height = window->base_height;
+}
+
+/**
+ * @brief Set the step size of the given window.
+ *
+ * @param window The window.
+ * @param step_width The step width.
+ * @param step_height The step height.
+ *
+ * This function sets the step size of @p window to @p step_width
+ * and *p step_height. If @p window is @c NULL, this functions does
+ * nothing.
+ */
+EAPI void
+ecore_win32_window_size_step_set(Ecore_Win32_Window *window,
+ unsigned int step_width,
+ unsigned int step_height)
+{
+ printf ("ecore_win32_window_size_step_set : %p %d %d\n", window, step_width, step_height);
+ if (!window) return;
+
+ window->step_width = step_width;
+ window->step_height = step_height;
+}
+
+/**
+ * @brief Get the step size of the given window.
+ *
+ * @param window The window.
+ * @param step_width The step width.
+ * @param step_height The bas height.
+ *
+ * This function fills the step size of @p window in the buffers
+ * @p step_width and *p step_height. They both can be @c NULL. If
+ * @p window is @c NULL, this functions does nothing.
+ */
+EAPI void
+ecore_win32_window_size_step_get(Ecore_Win32_Window *window,
+ unsigned int *step_width,
+ unsigned int *step_height)
+{
+ if (!window) return;
+
+ printf ("ecore_win32_window_size_step_get : %p %d %d\n", window, window->step_width, window->step_height);
+ if (step_width) *step_width = window->step_width;
+ if (step_height) *step_height = window->step_height;
+}
+
+/**
+ * @brief Show the given window.
+ *
+ * @param window The window to show.
+ *
+ * This function shows @p window. If @p window is @c NULL, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_show(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("showing window");
+
+ ShowWindow(window->window, SW_SHOWNORMAL);
+ if (!UpdateWindow(window->window))
+ {
+ ERR("UpdateWindow() failed");
+ }
+}
+
+/* FIXME: seems to block the taskbar */
+/**
+ * @brief Hide the given window.
+ *
+ * @param window The window to show.
+ *
+ * This function hides @p window. If @p window is @c NULL, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_hide(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("hiding window");
+
+ ShowWindow(window->window, SW_HIDE);
+}
+
+/**
+ * @brief Place the given window at the top of the Z order.
+ *
+ * @param window The window to place at the top.
+ *
+ * This function places @p window at the top of the Z order. If
+ * @p window is @c NULL, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_raise(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("raising window");
+
+ if (!SetWindowPos(window->window,
+ HWND_TOP, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE))
+ {
+ ERR("SetWindowPos() failed");
+ }
+}
+
+/**
+ * @brief Place the given window at the bottom of the Z order.
+ *
+ * @param window The window to place at the bottom.
+ *
+ * This function places @p window at the bottom of the Z order. If
+ * @p window is @c NULL, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_lower(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("lowering window");
+
+ if (!SetWindowPos(window->window,
+ HWND_BOTTOM, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE))
+ {
+ ERR("SetWindowPos() failed");
+ }
+}
+
+/**
+ * @brief Set the title of the given window.
+ *
+ * @param window The window to set the title.
+ * @param title The new title.
+ *
+ * This function sets the title of @p window to @p title. If @p window
+ * is @c NULL, or if @p title is @c NULL or empty, or on error, this
+ * function does nothing.
+ */
+EAPI void
+ecore_win32_window_title_set(Ecore_Win32_Window *window,
+ const char *title)
+{
+ if (!window) return;
+
+ if (!title || !title[0]) return;
+
+ INF("setting window title");
+
+ if (!SetWindowText(window->window, title))
+ {
+ ERR("SetWindowText() failed");
+ }
+}
+
+/**
+ * @brief Set the focus to the given window.
+ *
+ * @param window The window to give focus to.
+ *
+ * This function gives the focus to @p window. If @p window is
+ * @c NULL, this function does nothing.
+ */
+EAPI void
+ecore_win32_window_focus(Ecore_Win32_Window *window)
+{
+ if (!window) return;
+
+ INF("focusing window");
+
+ if (!SetFocus(window->window))
+ {
+ ERR("SetFocus() failed");
+ }
+}
+
+/**
+ * @brief Get the current focused window.
+ *
+ * @return The window that has focus.
+ *
+ * This function returns the window that has focus. If the calling
+ * thread's message queue does not have an associated window with the
+ * keyboard focus, the return value is @c NULL.
+ *
+ * @note Even if the returned value is @c NULL, another thread's queue
+ * may be associated with a window that has the keyboard focus.
+ *
+ * @note The returned value is of type HWND.
+ */
+EAPI void *
+ecore_win32_window_focus_get(void)
+{
+ HWND focused;
+
+ INF("getting focused window");
+
+ focused = GetFocus();
+ if (!focused)
+ {
+ ERR("GetFocus() failed");
+ return NULL;
+ }
+
+ return focused;
+}
+
+/**
+ * @brief Iconify or restore the given window.
+ *
+ * @param window The window.
+ * @param on @c EINA_TRUE to iconify the window, @c EINA_FALSE to restore it.
+ *
+ * This function iconify or restore @p window. If @p on is set to @c EINA_TRUE,
+ * the window will be iconified, if it is set to @c EINA_FALSE, it will be
+ * restored. If @p window is @c NULL or if the state does not change (like
+ * iconifying the window while it is already iconified), this function does
+ * nothing.
+ */
+EAPI void
+ecore_win32_window_iconified_set(Ecore_Win32_Window *window,
+ Eina_Bool on)
+{
+ if (!window) return;
+
+ if (((window->iconified) && (on)) ||
+ ((!window->iconified) && (!on)))
+ return;
+
+ INF("iconifying window: %s", on ? "yes" : "no");
+
+ ShowWindow(window->window, on ? SW_MINIMIZE : SW_RESTORE);
+ window->iconified = on;
+}
+
+/**
+ * @brief Remove or restore the border of the given window.
+ *
+ * @param window The window.
+ * @param on @c EINA_TRUE to remove the border, @c EINA_FALSE to restore it.
+ *
+ * This function remove or restore the border of @p window. If @p on is set to
+ * @c EINA_TRUE, the window will have no border, if it is set to @c EINA_FALSE,
+ * it will have a border. If @p window is @c NULL or if the state does not
+ * change (like setting to borderless while the window has no border), this
+ * function does nothing.
+ */
+EAPI void
+ecore_win32_window_borderless_set(Ecore_Win32_Window *window,
+ Eina_Bool on)
+{
+ RECT rect;
+ DWORD style;
+
+ if (!window) return;
+
+ if (((window->borderless) && (on)) ||
+ ((!window->borderless) && (!on)))
+ return;
+
+ INF("setting window without border: %s", on ? "yes" : "no");
+
+ style = GetWindowLong(window->window, GWL_STYLE);
+ if (on)
+ {
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+ return;
+ }
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_STYLE, style & ~(WS_CAPTION | WS_THICKFRAME)) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ }
+ else
+ {
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+ style |= WS_CAPTION | WS_THICKFRAME;
+ if (!AdjustWindowRect (&rect, style, FALSE))
+ {
+ ERR("AdjustWindowRect() failed");
+ return;
+ }
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_STYLE, style) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ }
+ if (!SetWindowPos(window->window, HWND_TOPMOST,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOMOVE | SWP_FRAMECHANGED))
+ {
+ ERR("SetWindowPos() failed");
+ return;
+ }
+
+ window->borderless = on;
+}
+
+/**
+ * @brief Set the given window to fullscreen.
+ *
+ * @param window The window.
+ * @param on @c EINA_TRUE for fullscreen mode, @c EINA_FALSE for windowed mode.
+ *
+ * This function set @p window to fullscreen or windowed mode. If @p on is set
+ * to @c EINA_TRUE, the window will be fullscreen, if it is set to
+ * @c EINA_FALSE, it will be windowed. If @p window is @c NULL or if the state
+ * does not change (like setting to fullscreen while the window is already
+ * fullscreen), this function does nothing.
+ */
+EAPI void
+ecore_win32_window_fullscreen_set(Ecore_Win32_Window *window,
+ Eina_Bool on)
+{
+ if (!window) return;
+
+ if (((window->fullscreen) && (on)) ||
+ ((!window->fullscreen) && (!on)))
+ return;
+
+ INF("setting fullscreen: %s", on ? "yes" : "no");
+
+ window->fullscreen = !!on;
+
+ if (on)
+ {
+ DWORD style;
+
+ if (!GetWindowRect(window->window, &window->rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+ if (!(window->style = GetWindowLong(window->window, GWL_STYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ style = window->style & ~WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX;
+ style |= WS_VISIBLE | WS_POPUP;
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_STYLE, style) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_EXSTYLE, WS_EX_TOPMOST) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ if (!SetWindowPos(window->window, HWND_TOPMOST, 0, 0,
+ GetSystemMetrics (SM_CXSCREEN),
+ GetSystemMetrics (SM_CYSCREEN),
+ SWP_NOCOPYBITS | SWP_SHOWWINDOW))
+ {
+ ERR("SetWindowPos() failed");
+ return;
+ }
+ }
+ else
+ {
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_STYLE, window->style) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ SetLastError(0);
+ if (!SetWindowLongPtr(window->window, GWL_EXSTYLE, 0) &&
+ (GetLastError() != 0))
+ {
+ ERR("SetWindowLongPtr() failed");
+ return;
+ }
+ if (!SetWindowPos(window->window, HWND_NOTOPMOST,
+ window->rect.left,
+ window->rect.top,
+ window->rect.right - window->rect.left,
+ window->rect.bottom - window->rect.top,
+ SWP_NOCOPYBITS | SWP_SHOWWINDOW))
+ {
+ ERR("SetWindowPos() failed");
+ return;
+ }
+ }
+}
+
+/**
+ * @brief Set the given cursor to the given window.
+ *
+ * @param window The window to modify the cursor.
+ * @param cursor The new cursor.
+ *
+ * This function sets @p cursor to @p window. @p cursor must have been
+ * obtained by ecore_win32_cursor_new() or
+ * ecore_win32_cursor_shaped_new(). If @p window or @p cursor is
+ * @c NULL, the function does nothing.
+ */
+EAPI void
+ecore_win32_window_cursor_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Cursor *cursor)
+{
+ INF("setting cursor");
+
+ if (!window || !cursor)
+ return;
+
+ if (!SetClassLongPtr(window->window,
+ GCLP_HCURSOR, (LONG_PTR)cursor))
+ {
+ ERR("SetClassLong() failed");
+ }
+}
+
+/**
+ * @brief Set the state of the given window.
+ *
+ * @param window The window to modify the state.
+ * @param state An array of the new states.
+ * @param num The number of states in the array.
+ *
+ * This function set the state of @p window. @p state is an array of
+ * states of size @p num. If @p window or @p state are @c NULL, or if
+ * @p num is less or equal than 0, the function does nothing.
+ */
+EAPI void
+ecore_win32_window_state_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_State *state,
+ unsigned int num)
+{
+ unsigned int i;
+
+ if (!window || !state || (num <= 0))
+ return;
+
+ INF("setting cursor state");
+
+ for (i = 0; i < num; i++)
+ {
+ switch (state[i])
+ {
+ case ECORE_WIN32_WINDOW_STATE_ICONIFIED:
+ window->state.iconified = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MODAL:
+ window->state.modal = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_STICKY:
+ window->state.sticky = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT:
+ window->state.maximized_vert = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ:
+ window->state.maximized_horz = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED:
+ window->state.maximized_horz = 1;
+ window->state.maximized_vert = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_SHADED:
+ window->state.shaded = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_HIDDEN:
+ window->state.hidden = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_FULLSCREEN:
+ window->state.fullscreen = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_ABOVE:
+ window->state.above = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_BELOW:
+ window->state.below = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION:
+ window->state.demands_attention = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_UNKNOWN:
+ /* nothing to be done */
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Apply the modification of the state to the given window.
+ *
+ * @param window The window.
+ * @param state The state to apply changes.
+ * @param set The value of the state change.
+ *
+ * This function applies the modification of the state @p state of
+ * @p window. @p set is used only for
+ * #ECORE_WIN32_WINDOW_STATE_ICONIFIED and
+ * #ECORE_WIN32_WINDOW_STATE_FULLSCREEN. If @p window is @c NULL, the
+ * function does nothing.
+ */
+EAPI void
+ecore_win32_window_state_request_send(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_State state,
+ unsigned int set)
+{
+ if (!window) return;
+
+ INF("sending cursor state");
+
+ switch (state)
+ {
+ case ECORE_WIN32_WINDOW_STATE_ICONIFIED:
+ if (window->state.iconified)
+ ecore_win32_window_iconified_set(window, set);
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MODAL:
+ window->state.modal = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_STICKY:
+ window->state.sticky = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT:
+ if (window->state.maximized_vert)
+ {
+ RECT rect;
+ int y;
+ int height;
+
+ if (!SystemParametersInfo(SPI_GETWORKAREA, 0,
+ &rect, 0))
+ {
+ ERR("SystemParametersInfo() failed");
+ break;
+ }
+ y = rect.top;
+ height = rect.bottom - rect.top;
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+ break;
+ }
+
+ if (!MoveWindow(window->window, rect.left, y,
+ rect.right - rect.left,
+ height,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+ }
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ:
+ if (window->state.maximized_horz)
+ {
+ RECT rect;
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+ break;
+ }
+
+ if (!MoveWindow(window->window, 0, rect.top,
+ GetSystemMetrics(SM_CXSCREEN),
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+ }
+ break;
+ case ECORE_WIN32_WINDOW_STATE_MAXIMIZED:
+ if (window->state.maximized_vert && window->state.maximized_horz)
+ {
+ RECT rect;
+
+ if (!SystemParametersInfo(SPI_GETWORKAREA, 0,
+ &rect, 0))
+ {
+ ERR("SystemParametersInfo() failed");
+ break;
+ }
+
+ if (!MoveWindow(window->window, 0, 0,
+ GetSystemMetrics(SM_CXSCREEN),
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+ }
+ break;
+ case ECORE_WIN32_WINDOW_STATE_SHADED:
+ window->state.shaded = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_HIDDEN:
+ window->state.hidden = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_FULLSCREEN:
+ if (window->state.fullscreen)
+ ecore_win32_window_fullscreen_set(window, set);
+ break;
+ case ECORE_WIN32_WINDOW_STATE_ABOVE:
+ if (window->state.above)
+ if (!SetWindowPos(window->window, HWND_TOP,
+ 0, 0,
+ 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW))
+ {
+ ERR("SetWindowPos() failed");
+ }
+ break;
+ case ECORE_WIN32_WINDOW_STATE_BELOW:
+ if (window->state.below)
+ if (!SetWindowPos(window->window, HWND_BOTTOM,
+ 0, 0,
+ 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW))
+ {
+ ERR("SetWindowPos() failed");
+ }
+ break;
+ case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION:
+ window->state.demands_attention = 1;
+ break;
+ case ECORE_WIN32_WINDOW_STATE_UNKNOWN:
+ /* nothing to be done */
+ break;
+ }
+}
+
+/**
+ * @brief Set the type of the given window.
+ *
+ * @param window The window to modify the type.
+ * @param type The nwindow types.
+ *
+ * This function set the type of @p window to @p type. If
+ * @p window is @c NULL, the function does nothing.
+ */
+EAPI void
+ecore_win32_window_type_set(Ecore_Win32_Window *window,
+ Ecore_Win32_Window_Type type)
+{
+ if (!window)
+ return;
+
+ INF("setting window type");
+
+ switch (type)
+ {
+ case ECORE_WIN32_WINDOW_TYPE_DESKTOP:
+ window->type.desktop = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_DOCK:
+ window->type.dock = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_TOOLBAR:
+ window->type.toolbar = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_MENU:
+ window->type.menu = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_UTILITY:
+ window->type.utility = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_SPLASH:
+ window->type.splash = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_DIALOG:
+ window->type.dialog = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_NORMAL:
+ window->type.normal = 1;
+ break;
+ case ECORE_WIN32_WINDOW_TYPE_UNKNOWN:
+ window->type.normal = 1;
+ break;
+ }
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_wince/Ecore_WinCE.h b/src/lib/ecore_wince/Ecore_WinCE.h
new file mode 100644
index 0000000000..20c197575a
--- /dev/null
+++ b/src/lib/ecore_wince/Ecore_WinCE.h
@@ -0,0 +1,314 @@
+#ifndef __ECORE_WINCE_H__
+#define __ECORE_WINCE_H__
+
+/*
+ * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND
+ * THE API MAY CHANGE.
+ */
+
+#ifndef ECORE_WINCE_WIP_OSXCKQSD
+# warning "You are using a work in progress API. This API is not stable"
+# warning "and is subject to change. You use this at your own risk."
+#endif
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_WINCE_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_WINCE_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WINCE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup Ecore_WinCE_Group Ecore_WinCE library
+ *
+ * @{
+ */
+
+
+/**
+ * @typedef Ecore_WinCE_Window
+ * Abstract type for a window.
+ */
+typedef struct _Ecore_WinCE_Window Ecore_WinCE_Window;
+
+
+/**
+ * @typedef Ecore_WinCE_Event_Mouse_In
+ * Event sent when the mouse enters the window.
+ */
+typedef struct _Ecore_WinCE_Event_Mouse_In Ecore_WinCE_Event_Mouse_In;
+
+/**
+ * @typedef Ecore_WinCE_Event_Mouse_Out
+ * Event sent when the mouse leaves the window.
+ */
+typedef struct _Ecore_WinCE_Event_Mouse_Out Ecore_WinCE_Event_Mouse_Out;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Focus_In
+ * Event sent when the window gets the focus.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Focus_In Ecore_WinCE_Event_Window_Focus_In;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Focus_Out
+ * Event sent when the window looses the focus.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Focus_Out Ecore_WinCE_Event_Window_Focus_Out;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Damage
+ * Event sent when the window is damaged.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Damage Ecore_WinCE_Event_Window_Damage;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Create
+ * Event sent when the window is created.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Create Ecore_WinCE_Event_Window_Create;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Destroy
+ * Event sent when the window is destroyed.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Destroy Ecore_WinCE_Event_Window_Destroy;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Hide
+ * Event sent when the window is hidden.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Hide Ecore_WinCE_Event_Window_Hide;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Show
+ * Event sent when the window is shown.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Show Ecore_WinCE_Event_Window_Show;
+
+/**
+ * @typedef Ecore_WinCE_Event_Window_Delete_Request
+ * Event sent when the window is deleted.
+ */
+typedef struct _Ecore_WinCE_Event_Window_Delete_Request Ecore_WinCE_Event_Window_Delete_Request;
+
+
+/**
+ * @struct _Ecore_WinCE_Event_Mouse_In
+ * Event sent when the mouse enters the window.
+ */
+struct _Ecore_WinCE_Event_Mouse_In
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate where the mouse entered */
+ int y; /**< The y coordinate where the mouse entered */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Mouse_Out
+ * Event sent when the mouse leaves the window.
+ */
+struct _Ecore_WinCE_Event_Mouse_Out
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate where the mouse leaved */
+ int y; /**< The y coordinate where the mouse leaved */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Focus_In
+ * Event sent when the window gets the focus.
+ */
+struct _Ecore_WinCE_Event_Window_Focus_In
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Focus_Out
+ * Event sent when the window looses the focus.
+ */
+struct _Ecore_WinCE_Event_Window_Focus_Out
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Damage
+ * Event sent when the window is damaged.
+ */
+struct _Ecore_WinCE_Event_Window_Damage
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ int x; /**< The x coordinate of the top left corner of the damaged region */
+ int y; /**< The y coordinate of the top left corner of the damaged region */
+ int width; /**< The width of the damaged region */
+ int height; /**< The height of the damaged region */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Create
+ * Event sent when the window is created.
+ */
+struct _Ecore_WinCE_Event_Window_Create
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Destroy
+ * Event sent when the window is destroyed.
+ */
+struct _Ecore_WinCE_Event_Window_Destroy
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Hide
+ * Event sent when the window is hidden.
+ */
+struct _Ecore_WinCE_Event_Window_Hide
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Show
+ * Event sent when the window is shown.
+ */
+struct _Ecore_WinCE_Event_Window_Show
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+/**
+ * @struct _Ecore_WinCE_Event_Window_Delete_Request
+ * Event sent when the window is deleted.
+ */
+struct _Ecore_WinCE_Event_Window_Delete_Request
+{
+ Ecore_WinCE_Window *window; /**< The window that received the event */
+ long time; /**< The time the event occurred */
+};
+
+
+EAPI extern int ECORE_WINCE_EVENT_MOUSE_IN; /**< Ecore_Event for the #Ecore_WinCE_Event_Mouse_In event */
+EAPI extern int ECORE_WINCE_EVENT_MOUSE_OUT; /**< Ecore_Event for the #Ecore_WinCE_Event_Mouse_Out event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_IN; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Focus_In event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Focus_Out event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_DAMAGE; /**< Ecore_Event for the Ecore_WinCE_Event_Damage event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_CREATE; /**< Ecore_Event for the Ecore_WinCE_Event_Create event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_DESTROY; /**< Ecore_Event for the Ecore_WinCE_Event_Destroy event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_HIDE; /**< Ecore_Event for the Ecore_WinCE_Event_Hide event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_SHOW; /**< Ecore_Event for the Ecore_WinCE_Event_Show event */
+EAPI extern int ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Delete_Request event */
+
+
+/* Core */
+
+EAPI int ecore_wince_init();
+EAPI int ecore_wince_shutdown();
+EAPI void ecore_wince_double_click_time_set(double t);
+EAPI double ecore_wince_double_click_time_get(void);
+EAPI long ecore_wince_current_time_get(void);
+
+/* Window */
+
+EAPI Ecore_WinCE_Window *ecore_wince_window_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_wince_window_free(Ecore_WinCE_Window *window);
+
+EAPI void *ecore_wince_window_hwnd_get(Ecore_WinCE_Window *window);
+
+EAPI void ecore_wince_window_move(Ecore_WinCE_Window *window,
+ int x,
+ int y);
+
+EAPI void ecore_wince_window_resize(Ecore_WinCE_Window *window,
+ int width,
+ int height);
+
+EAPI void ecore_wince_window_move_resize(Ecore_WinCE_Window *window,
+ int x,
+ int y,
+ int width,
+ int height);
+
+EAPI void ecore_wince_window_show(Ecore_WinCE_Window *window);
+
+EAPI void ecore_wince_window_hide(Ecore_WinCE_Window *window);
+
+EAPI void ecore_wince_window_title_set(Ecore_WinCE_Window *window,
+ const char *title);
+
+EAPI void ecore_wince_window_focus(Ecore_WinCE_Window *window);
+
+EAPI void *ecore_wince_window_focus_get(void);
+
+EAPI void ecore_wince_window_backend_set(Ecore_WinCE_Window *window, int backend);
+
+EAPI void ecore_wince_window_suspend_cb_set(Ecore_WinCE_Window *window, int (*suspend_cb)(int));
+
+EAPI void ecore_wince_window_resume_cb_set(Ecore_WinCE_Window *window, int (*resume_cb)(int));
+
+EAPI void ecore_wince_window_geometry_get(Ecore_WinCE_Window *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height);
+
+EAPI void ecore_wince_window_size_get(Ecore_WinCE_Window *window,
+ int *width,
+ int *height);
+
+EAPI void ecore_wince_window_fullscreen_set(Ecore_WinCE_Window *window,
+ Eina_Bool on);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ECORE_WINCE_H__ */
diff --git a/src/lib/ecore_wince/ecore_wince.c b/src/lib/ecore_wince/ecore_wince.c
new file mode 100644
index 0000000000..15da44c5e3
--- /dev/null
+++ b/src/lib/ecore_wince/ecore_wince.c
@@ -0,0 +1,400 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h> /* for printf */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+
+#include "Ecore_WinCE.h"
+#include "ecore_wince_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static int _ecore_wince_init_count = 0;
+
+LRESULT CALLBACK
+_ecore_wince_window_procedure(HWND window,
+ UINT message,
+ WPARAM window_param,
+ LPARAM data_param)
+{
+ Ecore_WinCE_Callback_Data *data;
+ POINTS pt;
+ DWORD coord;
+
+ data = (Ecore_WinCE_Callback_Data *)malloc(sizeof(Ecore_WinCE_Callback_Data));
+ if (!data) return DefWindowProc(window, message, window_param, data_param);
+
+ data->window = window;
+ data->message = message;
+ data->window_param = window_param;
+ data->data_param = data_param;
+ data->time = GetTickCount();
+ coord = GetMessagePos();
+ pt = MAKEPOINTS(coord);
+ data->x = pt.x;
+ data->y = pt.y;
+
+ switch (data->message)
+ {
+ /* Keyboard input notifications */
+ case WM_CHAR:
+ _ecore_wince_event_handle_key_press(data, 0);
+ break;
+ case WM_HOTKEY:
+ _ecore_wince_event_handle_key_press(data, 1);
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ _ecore_wince_event_handle_key_press(data, 1);
+ break;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ _ecore_wince_event_handle_key_release(data, 1);
+ break;
+ case WM_SETFOCUS:
+ _ecore_wince_event_handle_focus_in(data);
+ break;
+ case WM_KILLFOCUS:
+ _ecore_wince_event_handle_focus_out(data);
+ break;
+ /* Mouse input notifications */
+ case WM_LBUTTONDOWN:
+ _ecore_wince_event_handle_button_press(data, 1);
+ break;
+ case WM_LBUTTONUP:
+ _ecore_wince_event_handle_button_release(data, 1);
+ break;
+ case WM_MOUSEMOVE:
+ {
+ RECT rect;
+ Ecore_WinCE_Window *w = NULL;
+
+ w = (Ecore_WinCE_Window *)GetWindowLong(window, GWL_USERDATA);
+
+ if (GetClientRect(window, &rect))
+ {
+ POINT pt;
+
+ INF("mouse in window");
+
+ pt.x = LOWORD(data_param);
+ pt.y = HIWORD(data_param);
+ if (!PtInRect(&rect, pt))
+ {
+ if (w->pointer_is_in)
+ {
+ w->pointer_is_in = 0;
+ _ecore_wince_event_handle_leave_notify(data);
+ }
+ }
+ else
+ {
+ if (!w->pointer_is_in)
+ {
+ w->pointer_is_in = 1;
+ _ecore_wince_event_handle_enter_notify(data);
+ }
+ }
+ }
+ else
+ {
+ ERR("GetClientRect() failed");
+ }
+ _ecore_wince_event_handle_motion_notify(data);
+
+ break;
+ }
+ /* Window notifications */
+ case WM_CREATE:
+ _ecore_wince_event_handle_create_notify(data);
+ break;
+ case WM_DESTROY:
+ _ecore_wince_event_handle_destroy_notify(data);
+ break;
+ case WM_SHOWWINDOW:
+ if ((data->data_param == SW_OTHERUNZOOM) ||
+ (data->data_param == SW_OTHERZOOM))
+ break;
+
+ if (data->window_param)
+ _ecore_wince_event_handle_map_notify(data);
+ else
+ _ecore_wince_event_handle_unmap_notify(data);
+
+ break;
+ case WM_CLOSE:
+ _ecore_wince_event_handle_delete_request(data);
+ break;
+ /* GDI notifications */
+ case WM_ERASEBKGND:
+ return 1;
+ case WM_PAINT:
+ {
+ PAINTSTRUCT paint;
+
+ if (BeginPaint(window, &paint))
+ {
+ data->update = paint.rcPaint;
+ _ecore_wince_event_handle_expose(data);
+ EndPaint(window, &paint);
+ }
+ break;
+ }
+ default:
+ return DefWindowProc(window, message, window_param, data_param);
+ }
+
+ return 0;
+}
+
+static void
+_ecore_wince_error_print_cb(const Eina_Log_Domain *d EINA_UNUSED,
+ Eina_Log_Level level EINA_UNUSED,
+ const char *file EINA_UNUSED,
+ const char *fnc,
+ int line,
+ const char *fmt,
+ void *data EINA_UNUSED,
+ va_list args)
+{
+ fprintf(stderr, "[%s:%d] ", fnc, line);
+ vfprintf(stderr, fmt, args);
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+
+double _ecore_wince_double_click_time = 0.25;
+long _ecore_wince_event_last_time = 0;
+Ecore_WinCE_Window *_ecore_wince_event_last_window = NULL;
+HINSTANCE _ecore_wince_instance = NULL;
+int _ecore_wince_log_dom_global = -1;
+
+int ECORE_WINCE_EVENT_MOUSE_IN = 0;
+int ECORE_WINCE_EVENT_MOUSE_OUT = 0;
+int ECORE_WINCE_EVENT_WINDOW_FOCUS_IN = 0;
+int ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT = 0;
+int ECORE_WINCE_EVENT_WINDOW_DAMAGE = 0;
+int ECORE_WINCE_EVENT_WINDOW_CREATE = 0;
+int ECORE_WINCE_EVENT_WINDOW_DESTROY = 0;
+int ECORE_WINCE_EVENT_WINDOW_SHOW = 0;
+int ECORE_WINCE_EVENT_WINDOW_HIDE = 0;
+int ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST = 0;
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_WinCE_Group Ecore_WinCE library
+ *
+ * Ecore_WinCE is a library that wraps Windows CE graphic functions
+ * and integrate them nicely into the Ecore main loop.
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize the Ecore_WinCE library.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up the Windows CE graphic system. It returns 0 on
+ * failure, otherwise it returns the number of times it has already been
+ * called.
+ *
+ * When Ecore_WinCE is not used anymore, call ecore_wince_shutdown()
+ * to shut down the Ecore_WinCE library.
+ */
+EAPI int
+ecore_wince_init()
+{
+ WNDCLASS wc;
+
+ if (++_ecore_wince_init_count != 1)
+ return _ecore_wince_init_count;
+
+ if (!eina_init())
+ return --_ecore_wince_init_count;
+
+ eina_log_print_cb_set(_ecore_wince_error_print_cb, NULL);
+ _ecore_wince_log_dom_global = eina_log_domain_register
+ ("ecore_wince", ECORE_WINCE_DEFAULT_LOG_COLOR);
+ if (_ecore_wince_log_dom_global < 0)
+ {
+ EINA_LOG_ERR("Ecore_WinCE: Could not register log domain");
+ goto shutdown_eina;
+ }
+
+ if (!ecore_event_init())
+ {
+ ERR("Ecore_WinCE: Could not init ecore_event");
+ goto unregister_log_domain;
+ }
+
+ _ecore_wince_instance = GetModuleHandle(NULL);
+ if (!_ecore_wince_instance)
+ {
+ ERR("GetModuleHandle() failed");
+ goto shutdown_ecore_event;
+ }
+
+ memset (&wc, 0, sizeof (wc));
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = _ecore_wince_window_procedure;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = _ecore_wince_instance;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = ECORE_WINCE_WINDOW_CLASS;
+
+ if(!RegisterClass(&wc))
+ {
+ ERR("RegisterClass() failed");
+ goto free_library;
+ }
+
+ if (!ECORE_WINCE_EVENT_MOUSE_IN)
+ {
+ ECORE_WINCE_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_WINCE_EVENT_MOUSE_OUT = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_DAMAGE = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_CREATE = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_DESTROY = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_SHOW = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_HIDE = ecore_event_type_new();
+ ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
+ }
+
+ return _ecore_wince_init_count;
+
+ free_library:
+ FreeLibrary(_ecore_wince_instance);
+ shutdown_ecore_event:
+ ecore_event_shutdown();
+ unregister_log_domain:
+ eina_log_domain_unregister(_ecore_wince_log_dom_global);
+ shutdown_eina:
+ eina_shutdown();
+
+ return --_ecore_wince_init_count;
+}
+
+/**
+ * @brief Shut down the Ecore_WinCE library.
+ *
+ * @return 0 when the library is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Ecore_WinCE library. It returns 0 when it has
+ * been called the same number of times than ecore_wince_init(). In that case
+ * it shuts down all the Windows CE graphic system.
+ */
+EAPI int
+ecore_wince_shutdown()
+{
+ HWND task_bar;
+
+ if (--_ecore_wince_init_count != 0)
+ return _ecore_wince_init_count;
+
+ /* force task bar to be shown (in case the application exits */
+ /* while being fullscreen) */
+ task_bar = FindWindow(L"HHTaskBar", NULL);
+ if (task_bar)
+ {
+ ShowWindow(task_bar, SW_SHOW);
+ EnableWindow(task_bar, TRUE);
+ }
+
+ if (!UnregisterClass(ECORE_WINCE_WINDOW_CLASS, _ecore_wince_instance))
+ ERR("UnregisterClass() failed");
+
+ if (!FreeLibrary(_ecore_wince_instance))
+ ERR("FreeLibrary() failed");
+
+ _ecore_wince_instance = NULL;
+
+ ecore_event_shutdown();
+ eina_log_domain_unregister(_ecore_wince_log_dom_global);
+ _ecore_wince_log_dom_global = -1;
+ eina_shutdown();
+
+ return _ecore_wince_init_count;
+}
+
+/**
+ * @brief Set the timeout for a double and triple clicks to be flagged.
+ *
+ * @param t The time in seconds.
+ *
+ * This function sets the time @p t between clicks before the
+ * double_click flag is set in a button down event. If 3 clicks occur
+ * within double this time, the triple_click flag is also set.
+ */
+EAPI void
+ecore_wince_double_click_time_set(double t)
+{
+ if (t < 0.0) t = 0.0;
+ _ecore_wince_double_click_time = t;
+}
+
+/**
+ * @brief Retrieve the double and triple click flag timeout.
+ *
+ * @return The timeout for double clicks in seconds.
+ *
+ * This function returns the double clicks in seconds. If
+ * ecore_wince_double_click_time_set() has not been called, the
+ * default value is returned. See ecore_wince_double_click_time_set()
+ * for more informations.
+ */
+EAPI double
+ecore_wince_double_click_time_get(void)
+{
+ return _ecore_wince_double_click_time;
+}
+
+/**
+ * @brief Return the last event time.
+ *
+ * @return The last envent time.
+ *
+ * This function returns the last event time.
+ */
+EAPI long
+ecore_wince_current_time_get(void)
+{
+ return _ecore_wince_event_last_time;
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_wince/ecore_wince_event.c b/src/lib/ecore_wince/ecore_wince_event.c
new file mode 100644
index 0000000000..39430343e3
--- /dev/null
+++ b/src/lib/ecore_wince/ecore_wince_event.c
@@ -0,0 +1,1123 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+
+#include "Ecore_WinCE.h"
+#include "ecore_wince_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+typedef enum
+{
+ ECORE_WINCE_KEY_MASK_LSHIFT = 1 << 0,
+ ECORE_WINCE_KEY_MASK_RSHIFT = 1 << 1,
+ ECORE_WINCE_KEY_MASK_LCONTROL = 1 << 2,
+ ECORE_WINCE_KEY_MASK_RCONTROL = 1 << 3,
+ ECORE_WINCE_KEY_MASK_LMENU = 1 << 4,
+ ECORE_WINCE_KEY_MASK_RMENU = 1 << 5
+} Ecore_Wince_Key_Mask;
+
+static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_window = NULL;
+static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_last_window = NULL;
+static long _ecore_wince_mouse_down_last_time = 0;
+static long _ecore_wince_mouse_down_last_last_time = 0;
+static int _ecore_wince_mouse_down_did_triple = 0;
+static int _ecore_wince_mouse_up_count = 0;
+static Ecore_Wince_Key_Mask _ecore_wince_key_mask = 0;
+
+static void
+_ecore_wince_event_free_key_down(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Event_Key *e;
+
+ e = ev;
+ if (e->keyname) free((char *)e->keyname);
+ if (e->key) free((char *)e->key);
+ if (e->string) free((char *)e->string);
+ free(e);
+}
+
+static void
+_ecore_wince_event_free_key_up(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Event_Key *e;
+
+ e = ev;
+ if (e->keyname) free((char *)e->keyname);
+ if (e->key) free((char *)e->key);
+ if (e->string) free((char *)e->string);
+ free(e);
+}
+
+static int
+_ecore_wince_event_keystroke_get(int key,
+ Eina_Bool is_down,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose)
+{
+ char *kn;
+ char *ks;
+ char *kc;
+ int previous_key_state;
+
+ previous_key_state = msg->data_param & 0x40000000;
+
+ *keyname = NULL;
+ *keysymbol = NULL;
+ *keycompose = NULL;
+
+ switch (key)
+ {
+ /* Keystroke */
+ case VK_PRIOR:
+ kn = "Prior";
+ ks = "Prior";
+ kc = "Prior";
+ break;
+ case VK_NEXT:
+ kn = "Next";
+ ks = "Next";
+ kc = "Next";
+ break;
+ case VK_END:
+ kn = "End";
+ ks = "End";
+ kc = "End";
+ break;
+ case VK_HOME:
+ kn = "Home";
+ ks = "Home";
+ kc = "Home";
+ break;
+ case VK_LEFT:
+ kn = "Left";
+ ks = "Left";
+ kc = "Left";
+ break;
+ case VK_UP:
+ kn = "Up";
+ ks = "Up";
+ kc = "Up";
+ break;
+ case VK_RIGHT:
+ kn = "Right";
+ ks = "Right";
+ kc = "Right";
+ break;
+ case VK_DOWN:
+ kn = "Down";
+ ks = "Down";
+ kc = "Down";
+ break;
+ case VK_INSERT:
+ kn = "Insert";
+ ks = "Insert";
+ kc = "Insert";
+ break;
+ case VK_DELETE:
+ kn = "Delete";
+ ks = "Delete";
+ kc = "Delete";
+ break;
+ case VK_F1:
+ kn = "F1";
+ ks = "F1";
+ kc = "";
+ break;
+ case VK_F2:
+ kn = "F2";
+ ks = "F2";
+ kc = "";
+ break;
+ case VK_F3:
+ kn = "F3";
+ ks = "F3";
+ kc = "";
+ break;
+ case VK_F4:
+ kn = "F4";
+ ks = "F4";
+ kc = "";
+ break;
+ case VK_F5:
+ kn = "F5";
+ ks = "F5";
+ kc = "";
+ break;
+ case VK_F6:
+ kn = "F6";
+ ks = "F6";
+ kc = "";
+ break;
+ case VK_F7:
+ kn = "F7";
+ ks = "F7";
+ kc = "";
+ break;
+ case VK_F8:
+ kn = "F8";
+ ks = "F8";
+ kc = "";
+ break;
+ case VK_F9:
+ kn = "F9";
+ ks = "F9";
+ kc = "";
+ break;
+ case VK_F10:
+ kn = "F10";
+ ks = "F10";
+ kc = "";
+ break;
+ case VK_F11:
+ kn = "F11";
+ ks = "F11";
+ kc = "";
+ break;
+ case VK_F12:
+ kn = "F12";
+ ks = "F12";
+ kc = "";
+ break;
+ case VK_F13:
+ kn = "F13";
+ ks = "F13";
+ kc = "";
+ break;
+ case VK_F14:
+ kn = "F14";
+ ks = "F14";
+ kc = "";
+ break;
+ case VK_F15:
+ kn = "F15";
+ ks = "F15";
+ kc = "";
+ break;
+ case VK_F16:
+ kn = "F16";
+ ks = "F16";
+ kc = "";
+ break;
+ case VK_F17:
+ kn = "F17";
+ ks = "F17";
+ kc = "";
+ break;
+ case VK_F18:
+ kn = "F18";
+ ks = "F18";
+ kc = "";
+ break;
+ case VK_F19:
+ kn = "F19";
+ ks = "F19";
+ kc = "";
+ break;
+ case VK_F20:
+ /*
+ * VK_F20 indicates that an arrow key came from a rocker.
+ * This can safely be ignored.
+ */
+ return 0;
+ case VK_F21:
+ /*
+ * VK_F21 indicates that an arrow key came from a directional
+ * pad. This can safely be ignored.
+ */
+ return 0;
+ case VK_F22:
+ kn = "F22";
+ ks = "F22";
+ kc = "";
+ break;
+ case VK_F23:
+ /*
+ * Sent with VK_RETURN when doing an action (usually the middle
+ * button on a directional pad. This can safely be ignored.
+ */
+ return 0;
+ case VK_F24:
+ kn = "F24";
+ ks = "F24";
+ kc = "";
+ break;
+ case VK_APPS:
+ kn = "Application";
+ ks = "Application";
+ kc = "";
+ break;
+ case VK_SHIFT:
+ {
+ SHORT res;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LSHIFT);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LSHIFT;
+ kn = "Shift_L";
+ ks = "Shift_L";
+ kc = "";
+ }
+ res = GetKeyState(VK_RSHIFT);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RSHIFT;
+ kn = "Shift_R";
+ ks = "Shift_R";
+ kc = "";
+ }
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LSHIFT);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LSHIFT))
+ {
+ kn = "Shift_L";
+ ks = "Shift_L";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LSHIFT;
+ }
+ res = GetKeyState(VK_RSHIFT);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RSHIFT))
+ {
+ kn = "Shift_R";
+ ks = "Shift_R";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RSHIFT;
+ }
+ }
+ break;
+ }
+ case VK_CONTROL:
+ {
+ SHORT res;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LCONTROL);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LCONTROL;
+ kn = "Control_L";
+ ks = "Control_L";
+ kc = "";
+ break;
+ }
+ res = GetKeyState(VK_RCONTROL);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RCONTROL;
+ kn = "Control_R";
+ ks = "Control_R";
+ kc = "";
+ break;
+ }
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LCONTROL);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LCONTROL))
+ {
+ kn = "Control_L";
+ ks = "Control_L";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LCONTROL;
+ break;
+ }
+ res = GetKeyState(VK_RCONTROL);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RCONTROL))
+ {
+ kn = "Control_R";
+ ks = "Control_R";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RCONTROL;
+ break;
+ }
+ }
+ break;
+ }
+ case VK_MENU:
+ {
+ SHORT res;
+
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ res = GetKeyState(VK_LMENU);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LMENU;
+ kn = "Alt_L";
+ ks = "Alt_L";
+ kc = "";
+ }
+ res = GetKeyState(VK_RMENU);
+ if (res & 0x8000)
+ {
+ _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RMENU;
+ kn = "Alt_R";
+ ks = "Alt_R";
+ kc = "";
+ }
+ }
+ else /* is_up */
+ {
+ res = GetKeyState(VK_LMENU);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LMENU))
+ {
+ kn = "Alt_L";
+ ks = "Alt_L";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LMENU;
+ }
+ res = GetKeyState(VK_RMENU);
+ if (!(res & 0x8000) &&
+ (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RMENU))
+ {
+ kn = "Alt_R";
+ ks = "Alt_R";
+ kc = "";
+ _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RMENU;
+ }
+ }
+ break;
+ }
+ case VK_LWIN:
+ {
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ kn = "Super_L";
+ ks = "Super_L";
+ kc = "";
+ *modifiers |= ECORE_EVENT_MODIFIER_WIN;
+ }
+ else /* is_up */
+ {
+ kn = "Super_L";
+ ks = "Super_L";
+ kc = "";
+ *modifiers &= ~ECORE_EVENT_MODIFIER_WIN;
+ }
+ break;
+ }
+ case VK_RWIN:
+ {
+ if (is_down)
+ {
+ if (previous_key_state) return 0;
+ kn = "Super_R";
+ ks = "Super_R";
+ kc = "";
+ *modifiers |= ECORE_EVENT_MODIFIER_WIN;
+ }
+ else /* is_up */
+ {
+ kn = "Super_R";
+ ks = "Super_R";
+ kc = "";
+ *modifiers &= ~ECORE_EVENT_MODIFIER_WIN;
+ }
+ break;
+ }
+ default:
+ /* other non keystroke characters */
+ return 0;
+ }
+ *keyname = strdup(kn);
+ if (!*keyname) return 0;
+ *keysymbol = strdup(ks);
+ if (!*keysymbol)
+ {
+ free(*keyname);
+ *keyname = NULL;
+ return 0;
+ }
+ *keycompose = strdup(kc);
+ if (!*keycompose)
+ {
+ free(*keyname);
+ free(*keysymbol);
+ *keyname = NULL;
+ *keysymbol = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+_ecore_wince_event_char_get(int key,
+ char **keyname,
+ char **keysymbol,
+ char **keycompose)
+{
+ char kn[32];
+ char ks[32];
+ char kc[32];
+
+ *keyname = NULL;
+ *keysymbol = NULL;
+ *keycompose = NULL;
+
+ /* check control charaters such as ^a(key:1), ^z(key:26) */
+ if ((key > 0) && (key < 27) &&
+ ((GetKeyState(VK_CONTROL) & 0x8000) ||
+ (GetKeyState(VK_CONTROL) & 0x8000))) key += 96;
+
+ switch (key)
+ {
+ case VK_APP3:
+ case VK_BACK:
+ strncpy(kn, "BackSpace", 32);
+ strncpy(ks, "BackSpace", 32);
+ strncpy(kc, "BackSpace", 32);
+ break;
+ case VK_APP4:
+ case VK_TAB:
+ strncpy(kn, "Tab", 32);
+ strncpy(ks, "Tab", 32);
+ strncpy(kc, "Tab", 32);
+ break;
+ case VK_APP5:
+ case 0x0a:
+ /* Line feed (Shift + Enter) */
+ strncpy(kn, "LineFeed", 32);
+ strncpy(ks, "LineFeed", 32);
+ strncpy(kc, "LineFeed", 32);
+ break;
+ case VK_APP2:
+ case VK_RETURN:
+ strncpy(kn, "Return", 32);
+ strncpy(ks, "Return", 32);
+ strncpy(kc, "Return", 32);
+ break;
+ case VK_APP1:
+ case VK_ESCAPE:
+ strncpy(kn, "Escape", 32);
+ strncpy(ks, "Escape", 32);
+ strncpy(kc, "Escape", 32);
+ break;
+ case VK_SPACE:
+ strncpy(kn, "space", 32);
+ strncpy(ks, "space", 32);
+ strncpy(kc, " ", 32);
+ break;
+ default:
+ /* displayable characters */
+ printf (" * key : %d\n", key);
+ kn[0] = (TCHAR)key;
+ kn[1] = '\0';
+ ks[0] = (TCHAR)key;
+ ks[1] = '\0';
+ kc[0] = (TCHAR)key;
+ kc[1] = '\0';
+ break;
+ }
+ *keyname = strdup(kn);
+ if (!*keyname) return 0;
+ *keysymbol = strdup(ks);
+ if (!*keysymbol)
+ {
+ free(*keyname);
+ *keyname = NULL;
+ return 0;
+ }
+ *keycompose = strdup(kc);
+ if (!*keycompose)
+ {
+ free(*keyname);
+ free(*keysymbol);
+ *keyname = NULL;
+ *keysymbol = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+void
+_ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg,
+ int is_keystroke)
+{
+ Ecore_Event_Key *e;
+
+ INF("key pressed");
+
+ e = (Ecore_Event_Key *)malloc(sizeof(Ecore_Event_Key));
+ if (!e) return;
+
+ if (is_keystroke)
+ {
+ if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param),
+ EINA_TRUE,
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string))
+ {
+ free(e);
+ return;
+ }
+ }
+ else
+ {
+ if (!_ecore_wince_event_char_get(LOWORD(msg->window_param),
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string))
+ {
+ free(e);
+ return;
+ }
+ }
+
+ e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA);
+ e->event_window = e->window;
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_wince_event_free_key_down, NULL);
+}
+
+void
+_ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg,
+ int is_keystroke)
+{
+ Ecore_Event_Key *e;
+
+ INF("key released");
+
+ e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key));
+ if (!e) return;
+
+ if (is_keystroke)
+ {
+ if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param),
+ EINA_FALSE,
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string))
+ {
+ free(e);
+ return;
+ }
+ }
+ else
+ {
+ if (!_ecore_wince_event_char_get(LOWORD(msg->window_param),
+ (char **)&e->keyname,
+ (char **)&e->key,
+ (char **)&e->string))
+ {
+ free(e);
+ return;
+ }
+ }
+
+ e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA);
+ e->event_window = e->window;
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+
+ ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_wince_event_free_key_up, NULL);
+}
+
+void
+_ecore_wince_event_handle_button_press(Ecore_WinCE_Callback_Data *msg,
+ int button)
+{
+ Ecore_WinCE_Window *window;
+
+ INF("mouse button pressed");
+
+ window = (Ecore_WinCE_Window *)GetWindowLong(msg->window, GWL_USERDATA);
+
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = LOWORD(msg->data_param);
+ e->y = HIWORD(msg->data_param);
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Event_Mouse_Button *e;
+
+ if (_ecore_wince_mouse_down_did_triple)
+ {
+ _ecore_wince_mouse_down_last_window = NULL;
+ _ecore_wince_mouse_down_last_last_window = NULL;
+ _ecore_wince_mouse_down_last_time = 0;
+ _ecore_wince_mouse_down_last_last_time = 0;
+ }
+
+ e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->buttons = button;
+ e->x = LOWORD(msg->data_param);
+ e->y = HIWORD(msg->data_param);
+ e->timestamp = msg->time;
+
+ if (((e->timestamp - _ecore_wince_mouse_down_last_time) <= (long)(1000 * _ecore_wince_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window))
+ e->double_click = 1;
+
+ if (((e->timestamp - _ecore_wince_mouse_down_last_last_time) <= (long)(2 * 1000 * _ecore_wince_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_last_window))
+ {
+ e->triple_click = 1;
+ _ecore_wince_mouse_down_did_triple = 1;
+ }
+ else
+ _ecore_wince_mouse_down_did_triple = 0;
+
+ if (!e->double_click && !e->triple_click)
+ _ecore_wince_mouse_up_count = 0;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ if (!_ecore_wince_mouse_down_did_triple)
+ {
+ _ecore_wince_mouse_down_last_last_window = _ecore_wince_mouse_down_last_window;
+ _ecore_wince_mouse_down_last_window = (Ecore_WinCE_Window *)e->window;
+ _ecore_wince_mouse_down_last_last_time = _ecore_wince_mouse_down_last_time;
+ _ecore_wince_mouse_down_last_time = e->timestamp;
+ }
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_wince_event_handle_button_release(Ecore_WinCE_Callback_Data *msg,
+ int button)
+{
+ Ecore_WinCE_Window *window;
+
+ INF("mouse button released");
+
+ window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = LOWORD(msg->data_param);
+ e->y = HIWORD(msg->data_param);
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_Event_Mouse_Button *e;
+
+ e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->buttons = button;
+ e->x = LOWORD(msg->data_param);
+ e->y = HIWORD(msg->data_param);
+ e->timestamp = msg->time;
+
+ _ecore_wince_mouse_up_count++;
+
+ if ((_ecore_wince_mouse_up_count >= 2) &&
+ ((e->timestamp - _ecore_wince_mouse_down_last_time) <= (long)(1000 * _ecore_wince_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window))
+ e->double_click = 1;
+
+ if ((_ecore_wince_mouse_up_count >= 3) &&
+ ((e->timestamp - _ecore_wince_mouse_down_last_last_time) <= (long)(2 * 1000 * _ecore_wince_double_click_time)) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window) &&
+ (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_last_window))
+ e->triple_click = 1;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_wince_event_handle_motion_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_Event_Mouse_Move *e;
+
+ INF("mouse moved");
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA);
+ e->event_window = e->window;
+ e->x = LOWORD(msg->data_param);
+ e->y = HIWORD(msg->data_param);
+ e->timestamp = msg->time;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_enter_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Window *window;
+
+ INF("mouse in");
+
+ window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_WinCE_Event_Mouse_In *e;
+
+ e = (Ecore_WinCE_Event_Mouse_In *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_In));
+ if (!e) return;
+
+ e->window = window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->time = msg->time;
+
+ _ecore_wince_event_last_time = e->time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_MOUSE_IN, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_wince_event_handle_leave_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Window *window;
+
+ INF("mouse out");
+
+ window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+
+ {
+ Ecore_Event_Mouse_Move *e;
+
+ e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move));
+ if (!e) return;
+
+ e->window = (Ecore_Window)window;
+ e->event_window = e->window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->timestamp = msg->time;
+
+ _ecore_wince_event_last_time = e->timestamp;
+ _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL);
+ }
+
+ {
+ Ecore_WinCE_Event_Mouse_Out *e;
+
+ e = (Ecore_WinCE_Event_Mouse_Out *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Out));
+ if (!e) return;
+
+ e->window = window;
+ e->x = msg->x;
+ e->y = msg->y;
+ e->time = msg->time;
+
+ _ecore_wince_event_last_time = e->time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_MOUSE_OUT, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Focus_In *e;
+ Ecore_WinCE_Window *window;
+
+ INF("focus in");
+
+ e = (Ecore_WinCE_Event_Window_Focus_In *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Focus_In));
+ if (!e) return;
+
+ window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ if (window->resume_cb)
+ window->resume_cb(window->backend);
+
+ e->window = window;
+
+ e->time = _ecore_wince_event_last_time;
+ _ecore_wince_event_last_time = e->time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Focus_Out *e;
+ Ecore_WinCE_Window *window;
+
+ INF("focus out");
+
+ e = (Ecore_WinCE_Event_Window_Focus_Out *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Focus_Out));
+ if (!e) return;
+
+ window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+ if (window->suspend_cb)
+ window->suspend_cb(window->backend);
+
+ e->window = window;
+
+ e->time = _ecore_wince_event_last_time;
+ _ecore_wince_event_last_time = e->time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_expose(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Damage *e;
+
+ INF("window expose");
+
+ e = (Ecore_WinCE_Event_Window_Damage *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Damage));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->x = msg->update.left;
+ e->y = msg->update.top;
+ e->width = msg->update.right - msg->update.left;
+ e->height = msg->update.bottom - msg->update.top;
+ INF("window expose size: %dx%d", e->width, e->height);
+
+ e->time = _ecore_wince_event_last_time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_create_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Create *e;
+
+ INF("window create notify");
+
+ e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Create));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->time = _ecore_wince_event_last_time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_CREATE, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_destroy_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Destroy *e;
+
+ INF("window destroy notify");
+
+ e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Destroy));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->time = _ecore_wince_event_last_time;
+/* if (e->window == _ecore_wince_event_last_window) _ecore_wince_event_last_window = NULL; */
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DESTROY, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_map_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Show *e;
+
+ INF("window map notify");
+
+ e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Show));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->time = _ecore_wince_event_last_time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_SHOW, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_unmap_notify(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Hide *e;
+
+ INF("window unmap notify");
+
+ e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Hide));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->time = _ecore_wince_event_last_time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_HIDE, e, NULL, NULL);
+}
+
+void
+_ecore_wince_event_handle_delete_request(Ecore_WinCE_Callback_Data *msg)
+{
+ Ecore_WinCE_Event_Window_Delete_Request *e;
+
+ INF("window delete request");
+
+ e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Delete_Request));
+ if (!e) return;
+
+ e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA);
+ if (!e->window)
+ {
+ free(e);
+ return;
+ }
+
+ e->time = _ecore_wince_event_last_time;
+
+ ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL);
+}
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
diff --git a/src/lib/ecore_wince/ecore_wince_private.h b/src/lib/ecore_wince/ecore_wince_private.h
new file mode 100644
index 0000000000..b506312f99
--- /dev/null
+++ b/src/lib/ecore_wince/ecore_wince_private.h
@@ -0,0 +1,85 @@
+#ifndef __ECORE_WINCE_PRIVATE_H__
+#define __ECORE_WINCE_PRIVATE_H__
+
+
+/* logging messages macros */
+extern int _ecore_wince_log_dom_global;
+
+#ifdef ECORE_WINCE_DEFAULT_LOG_COLOR
+#undef ECORE_WINCE_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_WINCE_DEFAULT_LOG_COLOR EINA_COLOR_LIGHTBLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_wince_log_dom_global , __VA_ARGS__)
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_wince_log_dom_global , __VA_ARGS__)
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_wince_log_dom_global , __VA_ARGS__)
+
+#define ECORE_WINCE_WINDOW_CLASS L"Ecore_WinCE_Window_Class"
+
+
+typedef struct _Ecore_WinCE_Callback_Data Ecore_WinCE_Callback_Data;
+
+struct _Ecore_WinCE_Callback_Data
+{
+ RECT update;
+ HWND window;
+ unsigned int message;
+ WPARAM window_param;
+ LPARAM data_param;
+ long time;
+ int x;
+ int y;
+};
+
+
+typedef int (*ecore_wince_suspend_cb) (int);
+typedef int (*ecore_wince_resume_cb) (int);
+
+
+struct _Ecore_WinCE_Window
+{
+ HWND window;
+
+ int backend;
+ ecore_wince_suspend_cb suspend_cb;
+ ecore_wince_resume_cb resume_cb;
+
+ RECT rect; /* used to go fullscreen to normal */
+
+ unsigned int pointer_is_in : 1;
+ unsigned int fullscreen : 1;
+};
+
+extern HINSTANCE _ecore_wince_instance;
+extern double _ecore_wince_double_click_time;
+extern long _ecore_wince_event_last_time;
+extern Ecore_WinCE_Window *_ecore_wince_event_last_window;
+
+
+void _ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg, int is_keystroke);
+void _ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg, int is_keystroke);
+void _ecore_wince_event_handle_button_press(Ecore_WinCE_Callback_Data *msg, int button);
+void _ecore_wince_event_handle_button_release(Ecore_WinCE_Callback_Data *msg, int button);
+void _ecore_wince_event_handle_motion_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_enter_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_leave_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_expose(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_create_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_destroy_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_map_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_unmap_notify(Ecore_WinCE_Callback_Data *msg);
+void _ecore_wince_event_handle_delete_request(Ecore_WinCE_Callback_Data *msg);
+
+
+#endif /* __ECORE_WINCE_PRIVATE_H__ */
diff --git a/src/lib/ecore_wince/ecore_wince_window.c b/src/lib/ecore_wince/ecore_wince_window.c
new file mode 100644
index 0000000000..49a6312da3
--- /dev/null
+++ b/src/lib/ecore_wince/ecore_wince_window.c
@@ -0,0 +1,827 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Evil.h>
+#include <Eina.h>
+
+#include "Ecore_WinCE.h"
+#include "ecore_wince_private.h"
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+
+typedef BOOL (__stdcall *UnregisterFunc1Proc)(UINT, UINT);
+
+static int
+_ecore_wince_hardware_keys_register(HWND window)
+{
+ HINSTANCE core_dll;
+ UnregisterFunc1Proc unregister_fct;
+ int i;
+
+ core_dll = LoadLibrary(L"coredll.dll");
+ if (!core_dll)
+ {
+ ERR("LoadLibrary() failed");
+ return 0;
+ }
+
+ unregister_fct = (UnregisterFunc1Proc)GetProcAddress(core_dll, L"UnregisterFunc1");
+ if (!unregister_fct)
+ {
+ ERR("GetProcAddress() failed");
+ FreeLibrary(core_dll);
+ return 0;
+ }
+
+ for (i = 0xc1; i <= 0xcf; i++)
+ {
+ unregister_fct(MOD_WIN, i);
+ RegisterHotKey(window, i, MOD_WIN, i);
+ }
+
+ FreeLibrary(core_dll);
+
+ return 1;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ * Global *
+ *============================================================================*/
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**
+ * @addtogroup Ecore_WinCE_Group Ecore_WinCE library
+ *
+ * @{
+ */
+
+/**
+ * @brief Creates a new window.
+ *
+ * @param parent The parent window.
+ * @param x The x coordinate of the top-left corner of the window.
+ * @param y The y coordinate of the top-left corner of the window.
+ * @param width The width of the window.
+ * @param height The height of hte window.
+ * @return A newly allocated window.
+ *
+ * This function creates a new window which parent is @p parent. @p width and
+ * @p height are the size of the window content (the client part),
+ * without the border and title bar. @p x and @p y are the system
+ * coordinates of the top left cerner of the window (that is, of the
+ * title bar). This function returns a newly created window on
+ * success, and @c NULL on failure.
+ */
+EAPI Ecore_WinCE_Window *
+ecore_wince_window_new(Ecore_WinCE_Window *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ Ecore_WinCE_Window *w;
+ HWND window;
+ RECT rect;
+
+ INF("creating window");
+
+ w = (Ecore_WinCE_Window *)calloc(1, sizeof(Ecore_WinCE_Window));
+ if (!w)
+ {
+ ERR("malloc() failed");
+ return NULL;
+ }
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+ if (!AdjustWindowRectEx(&rect, WS_CAPTION | WS_SYSMENU | WS_VISIBLE, FALSE, WS_EX_TOPMOST))
+ {
+ ERR("AdjustWindowRectEx() failed");
+ free(w);
+ return NULL;
+ }
+
+ window = CreateWindowEx(WS_EX_TOPMOST,
+ ECORE_WINCE_WINDOW_CLASS,
+ L"",
+ WS_CAPTION | WS_SYSMENU | WS_VISIBLE,
+ x, y,
+ rect.right - rect.left, rect.bottom - rect.top,
+ parent ? ((Ecore_WinCE_Window *)parent)->window : NULL,
+ NULL, _ecore_wince_instance, NULL);
+ if (!window)
+ {
+ ERR("CreateWindowEx() failed");
+ free(w);
+ return NULL;
+ }
+
+ if (!_ecore_wince_hardware_keys_register(window))
+ {
+ ERR("_ecore_wince_hardware_keys_register() failed");
+ DestroyWindow(window);
+ free(w);
+ return NULL;
+ }
+
+ w->window = window;
+
+ SetLastError(0);
+ if (!SetWindowLong(window, GWL_USERDATA, (LONG)w) && (GetLastError() != 0))
+ {
+ ERR("SetWindowLong() failed");
+ DestroyWindow(window);
+ free(w);
+ return NULL;
+ }
+
+ w->pointer_is_in = 0;
+
+ return w;
+}
+
+/**
+ * @brief Free the given window.
+ *
+ * @param window The window to free.
+ *
+ * This function frees @p window. If @p window is @c NULL, this
+ * function does nothing.
+ */
+EAPI void
+ecore_wince_window_free(Ecore_WinCE_Window *window)
+{
+ if (!window) return;
+
+ INF("destroying window");
+
+ DestroyWindow(window->window);
+ free(window);
+}
+
+/**
+ * @brief Return the window HANDLE associated to the given window.
+ *
+ * @param window The window to retrieve the HANDLE from.
+ *
+ * This function returns the window HANDLE associated to @p window. If
+ * @p window is @c NULL, this function returns @c NULL.
+ */
+EAPI void *
+ecore_wince_window_hwnd_get(Ecore_WinCE_Window *window)
+{
+ if (!window)
+ return NULL;
+
+ return window->window;
+}
+
+/**
+ * @brief Move the given window to a given position.
+ *
+ * @param window The window to move.
+ * @param x The x coordinate of the destination position.
+ * @param y The y coordinate of the destination position.
+ *
+ * This function move @p window to the new position of coordinates @p x
+ * and @p y. If @p window is @c NULL, or if it is fullscreen, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_wince_window_move(Ecore_WinCE_Window *window,
+ int x,
+ int y)
+{
+ RECT rect;
+
+ if (!window || window->fullscreen)
+ return;
+
+ INF("moving window (%dx%d)", x, y);
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Resize the given window to a given size.
+ *
+ * @param window The window to resize.
+ * @param width The new width.
+ * @param height The new height.
+ *
+ * This function resize @p window to the new @p width and @p height.
+ * If @p window is @c NULL, or if it is fullscreen, or on error, this
+ * function does nothing.
+ */
+EAPI void
+ecore_wince_window_resize(Ecore_WinCE_Window *window,
+ int width,
+ int height)
+{
+ RECT rect;
+ DWORD style;
+ DWORD exstyle;
+ int x;
+ int y;
+
+ if (!window || window->fullscreen)
+ return;
+
+ INF("resizing window (%dx%d)", width, height);
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+
+ x = rect.left;
+ y = rect.top;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+ if (!(style = GetWindowLong(window->window, GWL_STYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!(exstyle = GetWindowLong(window->window, GWL_EXSTYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle))
+ {
+ ERR("AdjustWindowRectEx() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ FALSE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Move and resize the given window to a given position and size.
+ *
+ * @param window The window to move and resize.
+ * @param x The x coordinate of the destination position.
+ * @param y The x coordinate of the destination position.
+ * @param width The new width.
+ * @param height The new height.
+ *
+ * This function resize @p window to the new position of coordinates @p x
+ * and @p y and the new @p width and @p height. If @p window is @c NULL,
+ * or if it is fullscreen, or on error, this function does nothing.
+ */
+EAPI void
+ecore_wince_window_move_resize(Ecore_WinCE_Window *window,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ RECT rect;
+ DWORD style;
+ DWORD exstyle;
+
+ if (!window || window->fullscreen)
+ return;
+
+ INF("moving and resizing window (%dx%d %dx%d)", x, y, width, height);
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+ if (!(style = GetWindowLong(window->window, GWL_STYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!(exstyle = GetWindowLong(window->window, GWL_EXSTYLE)))
+ {
+ ERR("GetWindowLong() failed");
+ return;
+ }
+ if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle))
+ {
+ ERR("AdjustWindowRectEx() failed");
+ return;
+ }
+
+ if (!MoveWindow(window->window, x, y,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ TRUE))
+ {
+ ERR("MoveWindow() failed");
+ }
+}
+
+/**
+ * @brief Show the given window.
+ *
+ * @param window The window to show.
+ *
+ * This function shows @p window. If @p window is @c NULL, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_wince_window_show(Ecore_WinCE_Window *window)
+{
+ if (!window) return;
+
+ INF("showing window");
+
+ if (!ShowWindow(window->window, SW_SHOWNORMAL))
+ {
+ ERR("ShowWindow() failed");
+ return;
+ }
+ if (!UpdateWindow(window->window))
+ {
+ ERR("UpdateWindow() failed");
+ }
+ if (!SendMessage(window->window, WM_SHOWWINDOW, 1, 0))
+ {
+ ERR("SendMessage() failed");
+ }
+}
+
+/**
+ * @brief Hide the given window.
+ *
+ * @param window The window to show.
+ *
+ * This function hides @p window. If @p window is @c NULL, or on
+ * error, this function does nothing.
+ */
+EAPI void
+ecore_wince_window_hide(Ecore_WinCE_Window *window)
+{
+ if (!window) return;
+
+ INF("hiding window");
+
+ if (!ShowWindow(window->window, SW_HIDE))
+ {
+ ERR("ShowWindow() failed");
+ return;
+ }
+ if (!SendMessage(window->window, WM_SHOWWINDOW, 0, 0))
+ {
+ ERR("SendMessage() failed");
+ }
+}
+
+/**
+ * @brief Set the title of the given window.
+ *
+ * @param window The window to set the title.
+ * @param title The new title.
+ *
+ * This function sets the title of @p window to @p title. If @p window
+ * is @c NULL, or if @p title is @c NULL or empty, or on error, this
+ * function does nothing.
+ */
+EAPI void
+ecore_wince_window_title_set(Ecore_WinCE_Window *window,
+ const char *title)
+{
+ wchar_t *wtitle;
+
+ if (!window) return;
+
+ if (!title || !title[0]) return;
+
+ INF("setting window title");
+
+ wtitle = evil_char_to_wchar(title);
+ if (!wtitle) return;
+
+ if (!SetWindowText(window->window, wtitle))
+ {
+ ERR("SetWindowText() failed");
+ }
+ free(wtitle);
+}
+
+/**
+ * @brief Set the focus to the given window.
+ *
+ * @param window The window to give focus to.
+ *
+ * This function gives the focus to @p window. If @p window is
+ * @c NULL, this function does nothing.
+ */
+EAPI void
+ecore_wince_window_focus(Ecore_WinCE_Window *window)
+{
+ if (!window) return;
+
+ INF("focusing window");
+
+ if (!SetFocus(window->window))
+ {
+ ERR("SetFocus() failed");
+ }
+}
+
+/**
+ * @brief Get the current focused window.
+ *
+ * @return The window that has focus.
+ *
+ * This function returns the window that has focus. If the calling
+ * thread's message queue does not have an associated window with the
+ * keyboard focus, the return value is @c NULL.
+ *
+ * @note Even if the returned value is @c NULL, another thread's queue
+ * may be associated with a window that has the keyboard focus.
+ *
+ * @note The returned value is of type HWND.
+ */
+EAPI void *
+ecore_wince_window_focus_get(void)
+{
+ HWND focused;
+
+ INF("getting focused window");
+
+ focused = GetFocus();
+ if (!focused)
+ {
+ ERR("GetFocus() failed");
+ return NULL;
+ }
+
+ return focused;
+}
+
+/**
+ * @brief Set the graphic backend used for the given window.
+ *
+ * @param window The window.
+ * @param backend The backend.
+ *
+ * This function sets the graphic backend to use with @p window to
+ * @p backend. If @p window if @c NULL, this function does nothing.
+ *
+ * The valid values for @p backend are
+ *
+ * @li 0: automatic choice of the backend.
+ * @li 1: the framebuffer (fast but could be not well suported).
+ * @li 2: GAPI (less fast but almost always supported).
+ * @li 3: DirectDraw (less fast than GAPI but almost always
+ * supported).
+ * @li 4: GDI (the slowest but always supported).
+ *
+ * The @p backend is used only in Evas and Ecore_Evas. So this
+ * function should not be called if Ecore_Evas is used.
+ */
+EAPI void
+ecore_wince_window_backend_set(Ecore_WinCE_Window *window,
+ int backend)
+{
+ if (!window)
+ return;
+
+ INF("setting backend");
+
+ window->backend = backend;
+}
+
+/**
+ * @brief Set the suspend callback used for the given window.
+ *
+ * @param window The window.
+ * @param suspend_cb The suspend callback.
+ *
+ * This function sets the suspend callback to use with @p window to
+ * @p suspend_cb. If @p window if @c NULL, this function does nothing.
+ *
+ * The @p suspend_cb is used only in Evas and Ecore_Evas. So this
+ * function should not be called if Ecore_Evas is used.
+ */
+EAPI void
+ecore_wince_window_suspend_cb_set(Ecore_WinCE_Window *window, int (*suspend_cb)(int))
+{
+ if (!window)
+ return;
+
+ INF("setting suspend callback");
+
+ window->suspend_cb = suspend_cb;
+}
+
+/**
+ * @brief Set the resume callback used for the given window.
+ *
+ * @param window The window.
+ * @param resume_cb The resume callback.
+ *
+ * This function sets the resume callback to use with @p window to
+ * @p resume_cb. If @p window if @c NULL, this function does nothing.
+ *
+ * The @p resume_cb is used only in Evas and Ecore_Evas. So this
+ * function should not be called if Ecore_Evas is used.
+ */
+EAPI void
+ecore_wince_window_resume_cb_set(Ecore_WinCE_Window *window, int (*resume_cb)(int))
+{
+ if (!window)
+ return;
+
+ INF("setting resume callback");
+
+ window->resume_cb = resume_cb;
+}
+
+/**
+ * @brief Get the geometry of the given window.
+ *
+ * @param window The window to retrieve the geometry from.
+ * @param x The x coordinate of the position.
+ * @param y The x coordinate of the position.
+ * @param width The width.
+ * @param height The height.
+ *
+ * This function retrieves the position and size of @p window. @p x,
+ * @p y, @p width and @p height can be buffers that will be filled with
+ * the corresponding values. If one of them is @c NULL, nothing will
+ * be done for that parameter. If @p window is @c NULL, and if the
+ * buffers are not @c NULL, they will be filled with respectively 0,
+ * 0, the size of the screen and the height of the screen.
+ */
+EAPI void
+ecore_wince_window_geometry_get(Ecore_WinCE_Window *window,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ RECT rect;
+ int w;
+ int h;
+
+ INF("getting window geometry");
+
+ if (!window)
+ {
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = GetSystemMetrics(SM_CXSCREEN);
+ if (height) *height = GetSystemMetrics(SM_CYSCREEN);
+
+ return;
+ }
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = 0;
+ if (height) *height = 0;
+
+ return;
+ }
+
+ w = rect.right - rect.left;
+ h = rect.bottom - rect.top;
+
+ if (!GetWindowRect(window->window, &rect))
+ {
+ ERR("GetWindowRect() failed");
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (width) *width = 0;
+ if (height) *height = 0;
+
+ return;
+ }
+
+ if (x) *x = rect.left;
+ if (y) *y = rect.top;
+ if (width) *width = w;
+ if (height) *height = h;
+}
+
+/**
+ * @brief Get the size of the given window.
+ *
+ * @param window The window to retrieve the size from.
+ * @param width The width.
+ * @param height The height.
+ *
+ * This function retrieves the size of @p window. @p width and
+ * @p height can be buffers that will be filled with the corresponding
+ * values. If one of them is @c NULL, nothing will be done for that
+ * parameter. If @p window is @c NULL, and if the buffers are not
+ * @c NULL, they will be filled with respectively the size of the screen
+ * and the height of the screen.
+ */
+EAPI void
+ecore_wince_window_size_get(Ecore_WinCE_Window *window,
+ int *width,
+ int *height)
+{
+ RECT rect;
+
+ INF("getting window size");
+
+ if (!window)
+ {
+ if (width) *width = GetSystemMetrics(SM_CXSCREEN);
+ if (height) *height = GetSystemMetrics(SM_CYSCREEN);
+
+ return;
+ }
+
+ if (!GetClientRect(window->window, &rect))
+ {
+ ERR("GetClientRect() failed");
+
+ if (width) *width = 0;
+ if (height) *height = 0;
+ }
+
+ if (width) *width = rect.right - rect.left;
+ if (height) *height = rect.bottom - rect.top;
+}
+
+/**
+ * @brief Set the given window to fullscreen.
+ *
+ * @param window The window.
+ * @param on @c EINA_TRUE for fullscreen mode, @c EINA_FALSE for windowed mode.
+ *
+ * This function set @p window to fullscreen or windowed mode. If @p on is set
+ * to @c EINA_TRUE, the window will be fullscreen, if it is set to
+ * @c EINA_FALSE, it will be windowed. If @p window is @c NULL or if the state
+ * does not change (like setting to fullscreen while the window is already
+ * fullscreen), this function does nothing.
+ */
+EAPI void
+ecore_wince_window_fullscreen_set(Ecore_WinCE_Window *window,
+ Eina_Bool on)
+{
+ HWND task_bar;
+
+ if (!window) return;
+
+ if (((window->fullscreen) && (on)) ||
+ ((!window->fullscreen) && (!on)))
+ return;
+
+ INF("setting fullscreen: %s", on ? "yes" : "no");
+
+ window->fullscreen = !!on;
+
+ if (on)
+ {
+ /* save the position and size of the window */
+ if (!GetWindowRect(window->window, &window->rect))
+ {
+ ERR("GetWindowRect() failed");
+ return;
+ }
+
+ /* hide task bar */
+ task_bar = FindWindow(L"HHTaskBar", NULL);
+ if (!task_bar)
+ {
+ INF("FindWindow(): can not find task bar");
+ }
+ if (!ShowWindow(task_bar, SW_HIDE))
+ {
+ INF("ShowWindow(): task bar already hidden");
+ }
+ if (!EnableWindow(task_bar, FALSE))
+ {
+ INF("EnableWindow(): input already disabled");
+ }
+
+ /* style: visible + popup */
+ if (!SetWindowLong(window->window, GWL_STYLE, WS_POPUP | WS_VISIBLE))
+ {
+ INF("SetWindowLong() failed");
+ }
+
+ /* resize window to fit the entire screen */
+ if (!SetWindowPos(window->window, HWND_TOPMOST,
+ 0, 0,
+ GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN),
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED))
+ {
+ INF("SetWindowPos() failed");
+ }
+ /*
+ * It seems that SetWindowPos is not sufficient.
+ * Call MoveWindow with the correct size and force painting.
+ * Note that UpdateWindow (forcing repainting) is not sufficient
+ */
+ if (!MoveWindow(window->window,
+ 0, 0,
+ GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN),
+ TRUE))
+ {
+ INF("MoveWindow() failed");
+ }
+ }
+ else
+ {
+ /* show task bar */
+ task_bar = FindWindow(L"HHTaskBar", NULL);
+ if (!task_bar)
+ {
+ INF("FindWindow(): can not find task bar");
+ }
+ if (!ShowWindow(task_bar, SW_SHOW))
+ {
+ INF("ShowWindow(): task bar already visible");
+ }
+ if (!EnableWindow(task_bar, TRUE))
+ {
+ INF("EnableWindow(): input already enabled");
+ }
+
+ /* style: visible + caption + sysmenu */
+ if (!SetWindowLong(window->window, GWL_STYLE, WS_CAPTION | WS_SYSMENU | WS_VISIBLE))
+ {
+ INF("SetWindowLong() failed");
+ }
+ /* restaure the position and size of the window */
+ if (!SetWindowPos(window->window, HWND_TOPMOST,
+ window->rect.left,
+ window->rect.top,
+ window->rect.right - window->rect.left,
+ window->rect.bottom - window->rect.top,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED))
+ {
+ INF("SetWindowLong() failed");
+ }
+ /*
+ * It seems that SetWindowPos is not sufficient.
+ * Call MoveWindow with the correct size and force painting.
+ * Note that UpdateWindow (forcing repainting) is not sufficient
+ */
+ if (!MoveWindow(window->window,
+ window->rect.left,
+ window->rect.top,
+ window->rect.right - window->rect.left,
+ window->rect.bottom - window->rect.top,
+ TRUE))
+ {
+ INF("MoveWindow() failed");
+ }
+ }
+}
+
+/**
+ * @}
+ */
diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h
new file mode 100644
index 0000000000..b3fc0fabab
--- /dev/null
+++ b/src/lib/ecore_x/Ecore_X.h
@@ -0,0 +1,2407 @@
+#ifndef _ECORE_X_H
+#define _ECORE_X_H
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif // ifdef EAPI
+
+#ifdef _MSC_VER
+# ifdef BUILDING_DLL
+# define EAPI __declspec(dllexport)
+# else // ifdef BUILDING_DLL
+# define EAPI __declspec(dllimport)
+# endif // ifdef BUILDING_DLL
+#else // ifdef _MSC_VER
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else // if __GNUC__ >= 4
+# define EAPI
+# endif // if __GNUC__ >= 4
+# else // ifdef __GNUC__
+# define EAPI
+# endif // ifdef __GNUC__
+#endif // ifdef _MSC_VER
+
+#include <sys/types.h>
+
+/**
+ * @file
+ * @brief Ecore functions for dealing with the X Windows System
+ *
+ * Ecore_X provides a wrapper and convenience functions for using the
+ * X Windows System. Function groups for this part of the library
+ * include the following:
+ * @li @ref Ecore_X_Init_Group
+ * @li @ref Ecore_X_Display_Attr_Group
+ * @li @ref Ecore_X_Flush_Group
+ */
+
+typedef unsigned int Ecore_X_ID;
+#ifndef _ECORE_X_WINDOW_PREDEF
+typedef Ecore_X_ID Ecore_X_Window;
+#endif // ifndef _ECORE_X_WINDOW_PREDEF
+typedef void *Ecore_X_Visual;
+typedef Ecore_X_ID Ecore_X_Pixmap;
+typedef Ecore_X_ID Ecore_X_Drawable;
+#ifdef HAVE_ECORE_X_XCB
+typedef Ecore_X_ID Ecore_X_GC;
+#else // ifdef HAVE_ECORE_X_XCB
+typedef void *Ecore_X_GC;
+#endif /* HAVE_ECORE_X_XCB */
+typedef Ecore_X_ID Ecore_X_Atom;
+typedef Ecore_X_ID Ecore_X_Colormap;
+typedef Ecore_X_ID Ecore_X_Time;
+typedef Ecore_X_ID Ecore_X_Cursor;
+typedef void Ecore_X_Display;
+typedef void Ecore_X_Connection;
+typedef void Ecore_X_Screen;
+typedef Ecore_X_ID Ecore_X_Sync_Counter;
+typedef Ecore_X_ID Ecore_X_Sync_Alarm;
+typedef void Ecore_X_XRegion;
+
+typedef Ecore_X_ID Ecore_X_Randr_Output;
+typedef Ecore_X_ID Ecore_X_Randr_Crtc;
+typedef Ecore_X_ID Ecore_X_Randr_Mode;
+typedef unsigned short Ecore_X_Randr_Size_ID;
+typedef int Ecore_X_Randr_Screen;
+
+typedef Ecore_X_ID Ecore_X_Device;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+typedef struct _Ecore_X_Rectangle
+{
+ int x, y;
+ unsigned int width, height;
+} Ecore_X_Rectangle;
+
+typedef struct _Ecore_X_Icon
+{
+ unsigned int width, height;
+ unsigned int *data;
+} Ecore_X_Icon;
+
+typedef enum _Ecore_X_GC_Value_Mask
+{
+ ECORE_X_GC_VALUE_MASK_FUNCTION = (1L << 0),
+ ECORE_X_GC_VALUE_MASK_PLANE_MASK = (1L << 1),
+ ECORE_X_GC_VALUE_MASK_FOREGROUND = (1L << 2),
+ ECORE_X_GC_VALUE_MASK_BACKGROUND = (1L << 3),
+ ECORE_X_GC_VALUE_MASK_LINE_WIDTH = (1L << 4),
+ ECORE_X_GC_VALUE_MASK_LINE_STYLE = (1L << 5),
+ ECORE_X_GC_VALUE_MASK_CAP_STYLE = (1L << 6),
+ ECORE_X_GC_VALUE_MASK_JOIN_STYLE = (1L << 7),
+ ECORE_X_GC_VALUE_MASK_FILL_STYLE = (1L << 8),
+ ECORE_X_GC_VALUE_MASK_FILL_RULE = (1L << 9),
+ ECORE_X_GC_VALUE_MASK_TILE = (1L << 10),
+ ECORE_X_GC_VALUE_MASK_STIPPLE = (1L << 11),
+ ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X = (1L << 12),
+ ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y = (1L << 13),
+ ECORE_X_GC_VALUE_MASK_FONT = (1L << 14),
+ ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE = (1L << 15),
+ ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES = (1L << 16),
+ ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X = (1L << 17),
+ ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y = (1L << 18),
+ ECORE_X_GC_VALUE_MASK_CLIP_MASK = (1L << 19),
+ ECORE_X_GC_VALUE_MASK_DASH_OFFSET = (1L << 20),
+ ECORE_X_GC_VALUE_MASK_DASH_LIST = (1L << 21),
+ ECORE_X_GC_VALUE_MASK_ARC_MODE = (1L << 22)
+} Ecore_X_GC_Value_Mask;
+
+typedef enum _Ecore_X_Composite_Update_Type
+{
+ ECORE_X_COMPOSITE_UPDATE_AUTOMATIC,
+ ECORE_X_COMPOSITE_UPDATE_MANUAL
+} Ecore_X_Composite_Update_Type;
+
+/**
+ * @typedef _Ecore_X_Window_State
+ * Defines the different states of the window of Ecore_X.
+ */
+typedef enum _Ecore_X_Window_State
+{
+ ECORE_X_WINDOW_STATE_UNKNOWN = 0,
+ ECORE_X_WINDOW_STATE_ICONIFIED, /** The window is iconified. */
+ ECORE_X_WINDOW_STATE_MODAL, /** The window is a modal dialog box. */
+ ECORE_X_WINDOW_STATE_STICKY, /** The window manager should keep the window's position fixed
+ * even if the virtual desktop scrolls. */
+ ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, /** The window has the maximum vertical size. */
+ ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, /** The window has the maximum horizontal size. */
+ ECORE_X_WINDOW_STATE_SHADED, /** The window is shaded. */
+ ECORE_X_WINDOW_STATE_SKIP_TASKBAR, /** The window should not be included in the taskbar. */
+ ECORE_X_WINDOW_STATE_SKIP_PAGER, /** The window should not be included in the pager. */
+ ECORE_X_WINDOW_STATE_HIDDEN, /** The window is invisible (i.e. minimized/iconified) */
+ ECORE_X_WINDOW_STATE_FULLSCREEN, /** The window should fill the entire screen and have no
+ * window border/decorations */
+ ECORE_X_WINDOW_STATE_ABOVE,
+ ECORE_X_WINDOW_STATE_BELOW,
+ ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION
+} Ecore_X_Window_State;
+
+typedef enum _Ecore_X_Window_State_Action
+{
+ ECORE_X_WINDOW_STATE_ACTION_REMOVE,
+ ECORE_X_WINDOW_STATE_ACTION_ADD,
+ ECORE_X_WINDOW_STATE_ACTION_TOGGLE
+} Ecore_X_Window_State_Action;
+
+typedef enum _Ecore_X_Window_Stack_Mode
+{
+ ECORE_X_WINDOW_STACK_ABOVE = 0,
+ ECORE_X_WINDOW_STACK_BELOW = 1,
+ ECORE_X_WINDOW_STACK_TOP_IF = 2,
+ ECORE_X_WINDOW_STACK_BOTTOM_IF = 3,
+ ECORE_X_WINDOW_STACK_OPPOSITE = 4
+} Ecore_X_Window_Stack_Mode;
+
+typedef enum _Ecore_X_Randr_Orientation
+{
+ ECORE_X_RANDR_ORIENTATION_ROT_0 = (1 << 0),
+ ECORE_X_RANDR_ORIENTATION_ROT_90 = (1 << 1),
+ ECORE_X_RANDR_ORIENTATION_ROT_180 = (1 << 2),
+ ECORE_X_RANDR_ORIENTATION_ROT_270 = (1 << 3),
+ ECORE_X_RANDR_ORIENTATION_FLIP_X = (1 << 4),
+ ECORE_X_RANDR_ORIENTATION_FLIP_Y = (1 << 5)
+} Ecore_X_Randr_Orientation;
+
+typedef enum _Ecore_X_Randr_Connection_Status
+{
+ ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED = 0,
+ ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED = 1,
+ ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN = 2
+} Ecore_X_Randr_Connection_Status;
+
+typedef enum _Ecore_X_Randr_Output_Policy
+{
+ ECORE_X_RANDR_OUTPUT_POLICY_ABOVE = 1,
+ ECORE_X_RANDR_OUTPUT_POLICY_RIGHT = 2,
+ ECORE_X_RANDR_OUTPUT_POLICY_BELOW = 3,
+ ECORE_X_RANDR_OUTPUT_POLICY_LEFT = 4,
+ ECORE_X_RANDR_OUTPUT_POLICY_CLONE = 5,
+ ECORE_X_RANDR_OUTPUT_POLICY_NONE = 6,
+ ECORE_X_RANDR_OUTPUT_POLICY_ASK = 7
+} Ecore_X_Randr_Output_Policy;
+
+typedef enum _Ecore_X_Randr_Relative_Alignment
+{
+ ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE = 0,
+ ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL = 1,
+ ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR = 2
+} Ecore_X_Randr_Relative_Alignment;
+
+typedef enum _Ecore_X_Render_Subpixel_Order
+{
+ ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN = 0,
+ ECORE_X_RENDER_SUBPIXEL_ORDER_HORIZONTAL_RGB = 1,
+ ECORE_X_RENDER_SUBPIXEL_ORDER_HORIZONTAL_BGR = 2,
+ ECORE_X_RENDER_SUBPIXEL_ORDER_VERTICAL_RGB = 3,
+ ECORE_X_RENDER_SUBPIXEL_ORDER_VERTICAL_BGR = 4,
+ ECORE_X_RENDER_SUBPIXEL_ORDER_NONE = 5
+} Ecore_X_Render_Subpixel_Order;
+
+typedef enum _Ecore_X_Randr_Edid_Display_Interface_Type
+{
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_UNDEFINED,
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DVI,
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_A,
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_B,
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_MDDI,
+ ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT
+} Ecore_X_Randr_Edid_Display_Interface_Type;
+
+typedef enum _Ecore_X_Randr_Edid_Display_Colorscheme
+{
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_MONOCHROME_GRAYSCALE = 0x00,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB = 0x08,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_NON_RGB = 0x10,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_UNDEFINED = 0x18,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4 = 0x444000,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4 = 0x444,
+ ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2 = 0x422
+} Ecore_X_Randr_Edid_Display_Colorscheme;
+
+typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio
+{
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3 = 0x0,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9 = 0x1,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10 = 0x2,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4 = 0x4,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9 = 0x8
+} Ecore_X_Randr_Edid_Aspect_Ratio;
+
+#define ECORE_X_RANDR_EDID_UNKNOWN_VALUE -1
+
+#define ECORE_X_SELECTION_TARGET_TARGETS "TARGETS"
+#define ECORE_X_SELECTION_TARGET_TEXT "TEXT"
+#define ECORE_X_SELECTION_TARGET_COMPOUND_TEXT "COMPOUND_TEXT"
+#define ECORE_X_SELECTION_TARGET_STRING "STRING"
+#define ECORE_X_SELECTION_TARGET_UTF8_STRING "UTF8_STRING"
+#define ECORE_X_SELECTION_TARGET_FILENAME "FILENAME"
+
+#define ECORE_X_DND_VERSION 5
+
+typedef enum _Ecore_X_Selection
+{
+ ECORE_X_SELECTION_PRIMARY,
+ ECORE_X_SELECTION_SECONDARY,
+ ECORE_X_SELECTION_XDND,
+ ECORE_X_SELECTION_CLIPBOARD,
+ ECORE_X_SELECTION_OTHER
+} Ecore_X_Selection;
+
+typedef enum _Ecore_X_Event_Mode
+{
+ ECORE_X_EVENT_MODE_NORMAL,
+ ECORE_X_EVENT_MODE_WHILE_GRABBED,
+ ECORE_X_EVENT_MODE_GRAB,
+ ECORE_X_EVENT_MODE_UNGRAB
+} Ecore_X_Event_Mode;
+
+typedef enum _Ecore_X_Event_Detail
+{
+ ECORE_X_EVENT_DETAIL_ANCESTOR,
+ ECORE_X_EVENT_DETAIL_VIRTUAL,
+ ECORE_X_EVENT_DETAIL_INFERIOR,
+ ECORE_X_EVENT_DETAIL_NON_LINEAR,
+ ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL,
+ ECORE_X_EVENT_DETAIL_POINTER,
+ ECORE_X_EVENT_DETAIL_POINTER_ROOT,
+ ECORE_X_EVENT_DETAIL_DETAIL_NONE
+} Ecore_X_Event_Detail;
+
+typedef enum _Ecore_X_Event_Mask
+{
+ ECORE_X_EVENT_MASK_NONE = 0L,
+ ECORE_X_EVENT_MASK_KEY_DOWN = (1L << 0),
+ ECORE_X_EVENT_MASK_KEY_UP = (1L << 1),
+ ECORE_X_EVENT_MASK_MOUSE_DOWN = (1L << 2),
+ ECORE_X_EVENT_MASK_MOUSE_UP = (1L << 3),
+ ECORE_X_EVENT_MASK_MOUSE_IN = (1L << 4),
+ ECORE_X_EVENT_MASK_MOUSE_OUT = (1L << 5),
+ ECORE_X_EVENT_MASK_MOUSE_MOVE = (1L << 6),
+ ECORE_X_EVENT_MASK_WINDOW_DAMAGE = (1L << 15),
+ ECORE_X_EVENT_MASK_WINDOW_VISIBILITY = (1L << 16),
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE = (1L << 17),
+ ECORE_X_EVENT_MASK_WINDOW_RESIZE_MANAGE = (1L << 18),
+ ECORE_X_EVENT_MASK_WINDOW_MANAGE = (1L << 19),
+ ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE = (1L << 20),
+ ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE = (1L << 21),
+ ECORE_X_EVENT_MASK_WINDOW_PROPERTY = (1L << 22),
+ ECORE_X_EVENT_MASK_WINDOW_COLORMAP = (1L << 23),
+ ECORE_X_EVENT_MASK_WINDOW_GRAB = (1L << 24),
+ ECORE_X_EVENT_MASK_MOUSE_WHEEL = (1L << 29),
+ ECORE_X_EVENT_MASK_WINDOW_FOCUS_IN = (1L << 30),
+ ECORE_X_EVENT_MASK_WINDOW_FOCUS_OUT = (1L << 31)
+} Ecore_X_Event_Mask;
+
+typedef enum _Ecore_X_Gravity
+{
+ ECORE_X_GRAVITY_FORGET = 0,
+ ECORE_X_GRAVITY_UNMAP = 0,
+ ECORE_X_GRAVITY_NW = 1,
+ ECORE_X_GRAVITY_N = 2,
+ ECORE_X_GRAVITY_NE = 3,
+ ECORE_X_GRAVITY_W = 4,
+ ECORE_X_GRAVITY_CENTER = 5,
+ ECORE_X_GRAVITY_E = 6,
+ ECORE_X_GRAVITY_SW = 7,
+ ECORE_X_GRAVITY_S = 8,
+ ECORE_X_GRAVITY_SE = 9,
+ ECORE_X_GRAVITY_STATIC = 10
+} Ecore_X_Gravity;
+
+/* Needed for ecore_x_region_window_shape_set */
+typedef enum _Ecore_X_Shape_Type
+{
+ ECORE_X_SHAPE_BOUNDING,
+ ECORE_X_SHAPE_CLIP,
+ ECORE_X_SHAPE_INPUT
+} Ecore_X_Shape_Type;
+
+typedef enum _Ecore_X_Mapping_Type
+{
+ ECORE_X_MAPPING_MODIFIER,
+ ECORE_X_MAPPING_KEYBOARD,
+ ECORE_X_MAPPING_MOUSE
+} Ecore_X_Mapping_Type;
+
+typedef enum _Ecore_X_Randr_Property_Change
+{
+ ECORE_X_RANDR_PROPERTY_CHANGE_ADD,
+ ECORE_X_RANDR_PROPERTY_CHANGE_DEL
+} Ecore_X_Randr_Property_Change;
+
+typedef enum _Ecore_X_Netwm_Direction
+{
+ ECORE_X_NETWM_DIRECTION_SIZE_TL = 0,
+ ECORE_X_NETWM_DIRECTION_SIZE_T = 1,
+ ECORE_X_NETWM_DIRECTION_SIZE_TR = 2,
+ ECORE_X_NETWM_DIRECTION_SIZE_R = 3,
+ ECORE_X_NETWM_DIRECTION_SIZE_BR = 4,
+ ECORE_X_NETWM_DIRECTION_SIZE_B = 5,
+ ECORE_X_NETWM_DIRECTION_SIZE_BL = 6,
+ ECORE_X_NETWM_DIRECTION_SIZE_L = 7,
+ ECORE_X_NETWM_DIRECTION_MOVE = 8,
+ ECORE_X_NETWM_DIRECTION_CANCEL = 11,
+} Ecore_X_Netwm_Direction;
+
+/**
+ * @typedef _Ecore_X_Error_Code
+ * Defines the error codes of Ecore_X which wraps the X Window Systems
+ * protocol's errors.
+ *
+ * @since 1.7.0
+ */
+typedef enum _Ecore_X_Error_Code
+{
+ /** Everything is okay. */
+ ECORE_X_ERROR_CODE_SUCCESS = 0, /** Bad request code */
+ ECORE_X_ERROR_CODE_BAD_REQUEST = 1, /** Int parameter out of range */
+ ECORE_X_ERROR_CODE_BAD_VALUE = 2, /** Parameter not a Window */
+ ECORE_X_ERROR_CODE_BAD_WINDOW = 3, /** Parameter not a Pixmap */
+ ECORE_X_ERROR_CODE_BAD_PIXMAP = 4, /** Parameter not an Atom */
+ ECORE_X_ERROR_CODE_BAD_ATOM = 5, /** Parameter not a Cursor */
+ ECORE_X_ERROR_CODE_BAD_CURSOR = 6, /** Parameter not a Font */
+ ECORE_X_ERROR_CODE_BAD_FONT = 7, /** Parameter mismatch */
+ ECORE_X_ERROR_CODE_BAD_MATCH = 8, /** Parameter not a Pixmap or Window */
+ ECORE_X_ERROR_CODE_BAD_DRAWABLE = 9, /** Bad access */
+ ECORE_X_ERROR_CODE_BAD_ACCESS = 10, /** Insufficient resources */
+ ECORE_X_ERROR_CODE_BAD_ALLOC = 11, /** No such colormap */
+ ECORE_X_ERROR_CODE_BAD_COLOR = 12, /** Parameter not a GC */
+ ECORE_X_ERROR_CODE_BAD_GC = 13, /** Choice not in range or already used */
+ ECORE_X_ERROR_CODE_BAD_ID_CHOICE = 14, /** Font or color name doesn't exist */
+ ECORE_X_ERROR_CODE_BAD_NAME = 15, /** Request length incorrect */
+ ECORE_X_ERROR_CODE_BAD_LENGTH = 16, /** Server is defective */
+ ECORE_X_ERROR_CODE_BAD_IMPLEMENTATION = 17,
+} Ecore_X_Error_Code;
+
+typedef struct _Ecore_X_Event_Mouse_In Ecore_X_Event_Mouse_In;
+typedef struct _Ecore_X_Event_Mouse_Out Ecore_X_Event_Mouse_Out;
+typedef struct _Ecore_X_Event_Window_Focus_In Ecore_X_Event_Window_Focus_In;
+typedef struct _Ecore_X_Event_Window_Focus_Out Ecore_X_Event_Window_Focus_Out;
+typedef struct _Ecore_X_Event_Window_Keymap Ecore_X_Event_Window_Keymap;
+typedef struct _Ecore_X_Event_Window_Damage Ecore_X_Event_Window_Damage;
+typedef struct _Ecore_X_Event_Window_Visibility_Change Ecore_X_Event_Window_Visibility_Change;
+typedef struct _Ecore_X_Event_Window_Create Ecore_X_Event_Window_Create;
+typedef struct _Ecore_X_Event_Window_Destroy Ecore_X_Event_Window_Destroy;
+typedef struct _Ecore_X_Event_Window_Hide Ecore_X_Event_Window_Hide;
+typedef struct _Ecore_X_Event_Window_Show Ecore_X_Event_Window_Show;
+typedef struct _Ecore_X_Event_Window_Show_Request Ecore_X_Event_Window_Show_Request;
+typedef struct _Ecore_X_Event_Window_Reparent Ecore_X_Event_Window_Reparent;
+typedef struct _Ecore_X_Event_Window_Configure Ecore_X_Event_Window_Configure;
+typedef struct _Ecore_X_Event_Window_Configure_Request Ecore_X_Event_Window_Configure_Request;
+typedef struct _Ecore_X_Event_Window_Gravity Ecore_X_Event_Window_Gravity;
+typedef struct _Ecore_X_Event_Window_Resize_Request Ecore_X_Event_Window_Resize_Request;
+typedef struct _Ecore_X_Event_Window_Stack Ecore_X_Event_Window_Stack;
+typedef struct _Ecore_X_Event_Window_Stack_Request Ecore_X_Event_Window_Stack_Request;
+typedef struct _Ecore_X_Event_Window_Property Ecore_X_Event_Window_Property;
+typedef struct _Ecore_X_Event_Window_Colormap Ecore_X_Event_Window_Colormap;
+typedef struct _Ecore_X_Event_Mapping_Change Ecore_X_Event_Mapping_Change;
+typedef struct _Ecore_X_Event_Window_Mapping Ecore_X_Event_Window_Mapping;
+typedef struct _Ecore_X_Event_Selection_Clear Ecore_X_Event_Selection_Clear;
+typedef struct _Ecore_X_Event_Selection_Request Ecore_X_Event_Selection_Request;
+typedef struct _Ecore_X_Event_Selection_Notify Ecore_X_Event_Selection_Notify;
+typedef struct _Ecore_X_Event_Fixes_Selection_Notify Ecore_X_Event_Fixes_Selection_Notify;
+typedef struct _Ecore_X_Selection_Data Ecore_X_Selection_Data;
+typedef struct _Ecore_X_Selection_Data_Files Ecore_X_Selection_Data_Files;
+typedef struct _Ecore_X_Selection_Data_Text Ecore_X_Selection_Data_Text;
+typedef struct _Ecore_X_Selection_Data_Targets Ecore_X_Selection_Data_Targets;
+typedef struct _Ecore_X_Event_Xdnd_Enter Ecore_X_Event_Xdnd_Enter;
+typedef struct _Ecore_X_Event_Xdnd_Position Ecore_X_Event_Xdnd_Position;
+typedef struct _Ecore_X_Event_Xdnd_Status Ecore_X_Event_Xdnd_Status;
+typedef struct _Ecore_X_Event_Xdnd_Leave Ecore_X_Event_Xdnd_Leave;
+typedef struct _Ecore_X_Event_Xdnd_Drop Ecore_X_Event_Xdnd_Drop;
+typedef struct _Ecore_X_Event_Xdnd_Finished Ecore_X_Event_Xdnd_Finished;
+typedef struct _Ecore_X_Event_Client_Message Ecore_X_Event_Client_Message;
+typedef struct _Ecore_X_Event_Window_Shape Ecore_X_Event_Window_Shape;
+typedef struct _Ecore_X_Event_Screensaver_Notify Ecore_X_Event_Screensaver_Notify;
+typedef struct _Ecore_X_Event_Gesture_Notify_Flick Ecore_X_Event_Gesture_Notify_Flick;
+typedef struct _Ecore_X_Event_Gesture_Notify_Pan Ecore_X_Event_Gesture_Notify_Pan;
+typedef struct _Ecore_X_Event_Gesture_Notify_PinchRotation Ecore_X_Event_Gesture_Notify_PinchRotation;
+typedef struct _Ecore_X_Event_Gesture_Notify_Tap Ecore_X_Event_Gesture_Notify_Tap;
+typedef struct _Ecore_X_Event_Gesture_Notify_TapNHold Ecore_X_Event_Gesture_Notify_TapNHold;
+typedef struct _Ecore_X_Event_Gesture_Notify_Hold Ecore_X_Event_Gesture_Notify_Hold;
+typedef struct _Ecore_X_Event_Gesture_Notify_Group Ecore_X_Event_Gesture_Notify_Group;
+typedef struct _Ecore_X_Event_Sync_Counter Ecore_X_Event_Sync_Counter;
+typedef struct _Ecore_X_Event_Sync_Alarm Ecore_X_Event_Sync_Alarm;
+typedef struct _Ecore_X_Event_Screen_Change Ecore_X_Event_Screen_Change;
+typedef struct _Ecore_X_Event_Randr_Crtc_Change Ecore_X_Event_Randr_Crtc_Change;
+typedef struct _Ecore_X_Event_Randr_Output_Change Ecore_X_Event_Randr_Output_Change;
+typedef struct _Ecore_X_Event_Randr_Output_Property_Notify Ecore_X_Event_Randr_Output_Property_Notify;
+
+typedef struct _Ecore_X_Event_Window_Delete_Request Ecore_X_Event_Window_Delete_Request;
+typedef struct _Ecore_X_Event_Window_Move_Resize_Request Ecore_X_Event_Window_Move_Resize_Request;
+typedef struct _Ecore_X_Event_Window_State_Request Ecore_X_Event_Window_State_Request;
+typedef struct _Ecore_X_Event_Frame_Extents_Request Ecore_X_Event_Frame_Extents_Request;
+typedef struct _Ecore_X_Event_Ping Ecore_X_Event_Ping;
+typedef struct _Ecore_X_Event_Desktop_Change Ecore_X_Event_Desktop_Change;
+
+typedef struct _Ecore_X_Event_Startup_Sequence Ecore_X_Event_Startup_Sequence;
+
+typedef struct _Ecore_X_Event_Generic Ecore_X_Event_Generic;
+
+typedef struct _Ecore_X_Randr_Screen_Size Ecore_X_Randr_Screen_Size;
+typedef struct _Ecore_X_Randr_Screen_Size_MM Ecore_X_Randr_Screen_Size_MM;
+
+typedef struct _Ecore_X_Xdnd_Position Ecore_X_Xdnd_Position;
+
+struct _Ecore_X_Event_Mouse_In
+{
+ int modifiers;
+ int x, y;
+ Eina_Bool same_screen : 1;
+ struct
+ {
+ int x, y;
+ } root;
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Window root_win;
+ Ecore_X_Event_Mode mode;
+ Ecore_X_Event_Detail detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Mouse_Out
+{
+ int modifiers;
+ int x, y;
+ int same_screen;
+ struct
+ {
+ int x, y;
+ } root;
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Window root_win;
+ Ecore_X_Event_Mode mode;
+ Ecore_X_Event_Detail detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Focus_In
+{
+ Ecore_X_Window win;
+ Ecore_X_Event_Mode mode;
+ Ecore_X_Event_Detail detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Focus_Out
+{
+ Ecore_X_Window win;
+ Ecore_X_Event_Mode mode;
+ Ecore_X_Event_Detail detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Keymap
+{
+ Ecore_X_Window win;
+};
+
+struct _Ecore_X_Event_Window_Damage
+{
+ Ecore_X_Window win;
+ int x, y, w, h;
+ int count;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Visibility_Change
+{
+ Ecore_X_Window win;
+ int fully_obscured;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Create
+{
+ Ecore_X_Window win;
+ Ecore_X_Window parent;
+ int override;
+ int x, y, w, h;
+ int border;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Destroy
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Hide
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Show
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Show_Request
+{
+ Ecore_X_Window win;
+ Ecore_X_Window parent;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Reparent
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Window parent;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Configure
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Window abovewin;
+ int x, y, w, h;
+ int border;
+ Eina_Bool override : 1;
+ Eina_Bool from_wm : 1;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Configure_Request
+{
+ Ecore_X_Window win;
+ Ecore_X_Window parent_win;
+ Ecore_X_Window abovewin;
+ int x, y, w, h;
+ int border;
+ Ecore_X_Window_Stack_Mode detail;
+ unsigned long value_mask;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Gravity
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Resize_Request
+{
+ Ecore_X_Window win;
+ int w, h;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Stack
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Window_Stack_Mode detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Stack_Request
+{
+ Ecore_X_Window win;
+ Ecore_X_Window parent;
+ Ecore_X_Window_Stack_Mode detail;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Property
+{
+ Ecore_X_Window win;
+ Ecore_X_Atom atom;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Colormap
+{
+ Ecore_X_Window win;
+ Ecore_X_Colormap cmap;
+ Eina_Bool installed : 1;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Mapping_Change
+{
+ Ecore_X_Mapping_Type type;
+ int keycode;
+ int num;
+};
+
+struct _Ecore_X_Event_Selection_Clear
+{
+ Ecore_X_Window win;
+ Ecore_X_Selection selection;
+ Ecore_X_Atom atom;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Selection_Request
+{
+ Ecore_X_Window owner;
+ Ecore_X_Window requestor;
+ Ecore_X_Time time;
+ Ecore_X_Atom selection;
+ Ecore_X_Atom target;
+ Ecore_X_Atom property;
+};
+
+typedef enum
+{
+ ECORE_X_OWNER_CHANGE_REASON_NEW_OWNER,
+ ECORE_X_OWNER_CHANGE_REASON_DESTROY,
+ ECORE_X_OWNER_CHANGE_REASON_CLOSE
+} Ecore_X_Owner_Change_Reason;
+
+struct _Ecore_X_Event_Fixes_Selection_Notify
+{
+ Ecore_X_Window win;
+ Ecore_X_Window owner;
+ Ecore_X_Time time;
+ Ecore_X_Time selection_time;
+ Ecore_X_Selection selection;
+ Ecore_X_Atom atom;
+ Ecore_X_Owner_Change_Reason reason;
+};
+
+struct _Ecore_X_Event_Selection_Notify
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Selection selection;
+ Ecore_X_Atom atom;
+ char *target;
+ void *data;
+};
+
+struct _Ecore_X_Selection_Data
+{
+ enum
+ {
+ ECORE_X_SELECTION_CONTENT_NONE,
+ ECORE_X_SELECTION_CONTENT_TEXT,
+ ECORE_X_SELECTION_CONTENT_FILES,
+ ECORE_X_SELECTION_CONTENT_TARGETS,
+ ECORE_X_SELECTION_CONTENT_CUSTOM
+ } content;
+ unsigned char *data;
+ int length;
+ int format;
+ int (*free)(void *data);
+};
+
+struct _Ecore_X_Selection_Data_Files
+{
+ Ecore_X_Selection_Data data;
+ char **files;
+ int num_files;
+};
+
+struct _Ecore_X_Selection_Data_Text
+{
+ Ecore_X_Selection_Data data;
+ char *text;
+};
+
+struct _Ecore_X_Selection_Data_Targets
+{
+ Ecore_X_Selection_Data data;
+ char **targets;
+ int num_targets;
+};
+
+struct _Ecore_X_Event_Xdnd_Enter
+{
+ Ecore_X_Window win, source;
+
+ char **types;
+ int num_types;
+};
+
+struct _Ecore_X_Event_Xdnd_Position
+{
+ Ecore_X_Window win, source;
+ struct
+ {
+ int x, y;
+ } position;
+ Ecore_X_Atom action;
+};
+
+struct _Ecore_X_Xdnd_Position
+{
+ Ecore_X_Window win, prev;
+ struct
+ {
+ int x, y;
+ } position;
+};
+
+struct _Ecore_X_Event_Xdnd_Status
+{
+ Ecore_X_Window win, target;
+ Eina_Bool will_accept : 1;
+ Ecore_X_Rectangle rectangle;
+ Ecore_X_Atom action;
+};
+
+struct _Ecore_X_Event_Xdnd_Leave
+{
+ Ecore_X_Window win, source;
+};
+
+struct _Ecore_X_Event_Xdnd_Drop
+{
+ Ecore_X_Window win, source;
+ Ecore_X_Atom action;
+ struct
+ {
+ int x, y;
+ } position;
+};
+
+struct _Ecore_X_Event_Xdnd_Finished
+{
+ Ecore_X_Window win, target;
+ Eina_Bool completed : 1;
+ Ecore_X_Atom action;
+};
+
+struct _Ecore_X_Event_Client_Message
+{
+ Ecore_X_Window win;
+ Ecore_X_Atom message_type;
+ int format;
+ union
+ {
+ char b[20];
+ short s[10];
+ long l[5];
+ } data;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Shape
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Shape_Type type;
+ int x, y, w, h;
+ Eina_Bool shaped : 1;
+};
+
+struct _Ecore_X_Event_Screensaver_Notify
+{
+ Ecore_X_Window win;
+ Eina_Bool on : 1;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Sync_Counter
+{
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Sync_Alarm
+{
+ Ecore_X_Time time;
+ Ecore_X_Sync_Alarm alarm;
+};
+
+struct _Ecore_X_Randr_Screen_Size
+{
+ int width, height;
+};
+
+struct _Ecore_X_Randr_Screen_Size_MM
+{
+ int width, height, width_mm, height_mm;
+};
+
+struct _Ecore_X_Event_Screen_Change
+{
+ Ecore_X_Window win;
+ Ecore_X_Window root;
+ Ecore_X_Randr_Screen_Size_MM size; /* in pixel and millimeters */
+ Ecore_X_Time time;
+ Ecore_X_Time config_time;
+ Ecore_X_Randr_Orientation orientation;
+ Ecore_X_Render_Subpixel_Order subpixel_order;
+ Ecore_X_Randr_Size_ID size_id;
+};
+
+struct _Ecore_X_Event_Randr_Crtc_Change
+{
+ Ecore_X_Window win;
+ Ecore_X_Randr_Crtc crtc;
+ Ecore_X_Randr_Mode mode;
+ Ecore_X_Randr_Orientation orientation;
+ Eina_Rectangle geo;
+};
+
+struct _Ecore_X_Event_Randr_Output_Change
+{
+ Ecore_X_Window win;
+ Ecore_X_Randr_Output output;
+ Ecore_X_Randr_Crtc crtc;
+ Ecore_X_Randr_Mode mode;
+ Ecore_X_Randr_Orientation orientation;
+ Ecore_X_Randr_Connection_Status connection;
+ Ecore_X_Render_Subpixel_Order subpixel_order;
+};
+
+struct _Ecore_X_Event_Randr_Output_Property_Notify
+{
+ Ecore_X_Window win;
+ Ecore_X_Randr_Output output;
+ Ecore_X_Atom property;
+ Ecore_X_Time time;
+ Ecore_X_Randr_Property_Change state;
+};
+
+struct _Ecore_X_Event_Window_Delete_Request
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Title_Change
+{
+ Ecore_X_Window win;
+ char *title;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Visible_Title_Change
+{
+ Ecore_X_Window win;
+ char *title;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Icon_Name_Change
+{
+ Ecore_X_Window win;
+ char *name;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change
+{
+ Ecore_X_Window win;
+ char *name;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Client_Machine_Change
+{
+ Ecore_X_Window win;
+ char *name;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Name_Class_Change
+{
+ Ecore_X_Window win;
+ char *name;
+ char *clas;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Pid_Change
+{
+ Ecore_X_Window win;
+ pid_t pid;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Window_Prop_Desktop_Change
+{
+ Ecore_X_Window win;
+ long desktop;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Startup_Sequence
+{
+ Ecore_X_Window win;
+};
+
+struct _Ecore_X_Event_Window_Move_Resize_Request
+{
+ Ecore_X_Window win;
+ int x, y;
+ int direction;
+ int button;
+ int source;
+};
+
+struct _Ecore_X_Event_Window_State_Request
+{
+ Ecore_X_Window win;
+ Ecore_X_Window_State_Action action;
+ Ecore_X_Window_State state[2];
+ int source;
+};
+
+struct _Ecore_X_Event_Frame_Extents_Request
+{
+ Ecore_X_Window win;
+};
+
+struct _Ecore_X_Event_Ping
+{
+ Ecore_X_Window win;
+ Ecore_X_Window event_win;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Event_Desktop_Change
+{
+ Ecore_X_Window win;
+ unsigned int desk;
+ int source;
+};
+
+struct _Ecore_X_Event_Generic
+{
+ int extension;
+ int evtype;
+ unsigned int cookie;
+ void *data;
+};
+
+EAPI extern int ECORE_X_EVENT_ANY; /**< low level event dependent on
+ backend in use, if Xlib will be XEvent, if XCB will be xcb_generic_event_t.
+ @warning avoid using it.
+ */
+EAPI extern int ECORE_X_EVENT_MOUSE_IN;
+EAPI extern int ECORE_X_EVENT_MOUSE_OUT;
+EAPI extern int ECORE_X_EVENT_WINDOW_FOCUS_IN;
+EAPI extern int ECORE_X_EVENT_WINDOW_FOCUS_OUT;
+EAPI extern int ECORE_X_EVENT_WINDOW_KEYMAP;
+EAPI extern int ECORE_X_EVENT_WINDOW_DAMAGE;
+EAPI extern int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE;
+EAPI extern int ECORE_X_EVENT_WINDOW_CREATE;
+EAPI extern int ECORE_X_EVENT_WINDOW_DESTROY;
+EAPI extern int ECORE_X_EVENT_WINDOW_HIDE;
+EAPI extern int ECORE_X_EVENT_WINDOW_SHOW;
+EAPI extern int ECORE_X_EVENT_WINDOW_SHOW_REQUEST;
+EAPI extern int ECORE_X_EVENT_WINDOW_REPARENT;
+EAPI extern int ECORE_X_EVENT_WINDOW_CONFIGURE;
+EAPI extern int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST;
+EAPI extern int ECORE_X_EVENT_WINDOW_GRAVITY;
+EAPI extern int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST;
+EAPI extern int ECORE_X_EVENT_WINDOW_STACK;
+EAPI extern int ECORE_X_EVENT_WINDOW_STACK_REQUEST;
+EAPI extern int ECORE_X_EVENT_WINDOW_PROPERTY;
+EAPI extern int ECORE_X_EVENT_WINDOW_COLORMAP;
+EAPI extern int ECORE_X_EVENT_WINDOW_MAPPING;
+EAPI extern int ECORE_X_EVENT_MAPPING_CHANGE;
+EAPI extern int ECORE_X_EVENT_SELECTION_CLEAR;
+EAPI extern int ECORE_X_EVENT_SELECTION_REQUEST;
+EAPI extern int ECORE_X_EVENT_SELECTION_NOTIFY;
+EAPI extern int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY;
+EAPI extern int ECORE_X_EVENT_CLIENT_MESSAGE;
+EAPI extern int ECORE_X_EVENT_WINDOW_SHAPE;
+EAPI extern int ECORE_X_EVENT_SCREENSAVER_NOTIFY;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_PAN;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_TAP;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD;
+EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP;
+EAPI extern int ECORE_X_EVENT_SYNC_COUNTER;
+EAPI extern int ECORE_X_EVENT_SYNC_ALARM;
+EAPI extern int ECORE_X_EVENT_SCREEN_CHANGE;
+EAPI extern int ECORE_X_EVENT_RANDR_CRTC_CHANGE;
+EAPI extern int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE;
+EAPI extern int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY;
+EAPI extern int ECORE_X_EVENT_DAMAGE_NOTIFY;
+
+EAPI extern int ECORE_X_EVENT_WINDOW_DELETE_REQUEST;
+
+EAPI extern int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST;
+EAPI extern int ECORE_X_EVENT_WINDOW_STATE_REQUEST;
+EAPI extern int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST;
+EAPI extern int ECORE_X_EVENT_PING;
+EAPI extern int ECORE_X_EVENT_DESKTOP_CHANGE;
+
+EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW;
+EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE;
+EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE;
+EAPI extern int ECORE_X_EVENT_XKB_STATE_NOTIFY; /** @since 1.7 */
+EAPI extern int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY; /** @since 1.7 */
+
+EAPI extern int ECORE_X_EVENT_GENERIC;
+
+EAPI extern int ECORE_X_EVENT_XDND_ENTER;
+EAPI extern int ECORE_X_EVENT_XDND_POSITION;
+EAPI extern int ECORE_X_EVENT_XDND_STATUS;
+EAPI extern int ECORE_X_EVENT_XDND_LEAVE;
+EAPI extern int ECORE_X_EVENT_XDND_DROP;
+EAPI extern int ECORE_X_EVENT_XDND_FINISHED;
+
+EAPI extern int ECORE_X_MODIFIER_SHIFT; /**< @since 1.7 */
+EAPI extern int ECORE_X_MODIFIER_CTRL; /**< @since 1.7 */
+EAPI extern int ECORE_X_MODIFIER_ALT; /**< @since 1.7 */
+EAPI extern int ECORE_X_MODIFIER_WIN; /**< @since 1.7 */
+EAPI extern int ECORE_X_MODIFIER_ALTGR; /**< @since 1.7 */
+
+EAPI extern int ECORE_X_LOCK_SCROLL;
+EAPI extern int ECORE_X_LOCK_NUM;
+EAPI extern int ECORE_X_LOCK_CAPS;
+EAPI extern int ECORE_X_LOCK_SHIFT;
+
+EAPI extern int ECORE_X_RAW_BUTTON_PRESS; /**< @since 1.8 */
+EAPI extern int ECORE_X_RAW_BUTTON_RELEASE; /**< @since 1.8 */
+EAPI extern int ECORE_X_RAW_MOTION; /**< @since 1.8 */
+
+typedef enum _Ecore_X_WM_Protocol
+{
+ /** If enabled the window manager will be asked to send a
+ * delete message instead of just closing (destroying) the window. */
+ ECORE_X_WM_PROTOCOL_DELETE_REQUEST,
+
+ /** If enabled the window manager will be told that the window
+ * explicitly sets input focus. */
+ ECORE_X_WM_PROTOCOL_TAKE_FOCUS,
+
+ /** If enabled the window manager can ping the window to check
+ * if it is alive. */
+ ECORE_X_NET_WM_PROTOCOL_PING,
+
+ /** If enabled the window manager can sync updating with the
+ * window (?) */
+ ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST,
+
+ /** Number of defined items */
+ ECORE_X_WM_PROTOCOL_NUM
+} Ecore_X_WM_Protocol;
+
+typedef enum _Ecore_X_Window_Input_Mode
+{
+ /** The window can never be focused */
+ ECORE_X_WINDOW_INPUT_MODE_NONE,
+
+ /** The window can be focused by the WM but doesn't focus itself */
+ ECORE_X_WINDOW_INPUT_MODE_PASSIVE,
+
+ /** The window sets the focus itself if one of its sub-windows
+ * already is focused */
+ ECORE_X_WINDOW_INPUT_MODE_ACTIVE_LOCAL,
+
+ /** The window sets the focus itself even if another window
+ * is currently focused */
+ ECORE_X_WINDOW_INPUT_MODE_ACTIVE_GLOBAL
+} Ecore_X_Window_Input_Mode;
+
+/**
+ * @typedef _Ecore_X_Window_State_Hint
+ * Defines the different state hint of the window of Ecore_X.
+ */
+typedef enum _Ecore_X_Window_State_Hint
+{
+ /** Do not provide any state hint to the window manager */
+ ECORE_X_WINDOW_STATE_HINT_NONE = -1,
+
+ /** The window wants to remain hidden and NOT iconified */
+ ECORE_X_WINDOW_STATE_HINT_WITHDRAWN,
+
+ /** The window wants to be mapped normally */
+ ECORE_X_WINDOW_STATE_HINT_NORMAL,
+
+ /** The window wants to start in an iconified state */
+ ECORE_X_WINDOW_STATE_HINT_ICONIC
+} Ecore_X_Window_State_Hint;
+
+typedef enum _Ecore_X_Window_Type
+{
+ ECORE_X_WINDOW_TYPE_UNKNOWN = 0,
+ ECORE_X_WINDOW_TYPE_DESKTOP,
+ ECORE_X_WINDOW_TYPE_DOCK,
+ ECORE_X_WINDOW_TYPE_TOOLBAR,
+ ECORE_X_WINDOW_TYPE_MENU,
+ ECORE_X_WINDOW_TYPE_UTILITY,
+ ECORE_X_WINDOW_TYPE_SPLASH,
+ ECORE_X_WINDOW_TYPE_DIALOG,
+ ECORE_X_WINDOW_TYPE_NORMAL,
+ ECORE_X_WINDOW_TYPE_DROPDOWN_MENU,
+ ECORE_X_WINDOW_TYPE_POPUP_MENU,
+ ECORE_X_WINDOW_TYPE_TOOLTIP,
+ ECORE_X_WINDOW_TYPE_NOTIFICATION,
+ ECORE_X_WINDOW_TYPE_COMBO,
+ ECORE_X_WINDOW_TYPE_DND
+} Ecore_X_Window_Type;
+
+typedef enum _Ecore_X_Action
+{
+ ECORE_X_ACTION_MOVE,
+ ECORE_X_ACTION_RESIZE,
+ ECORE_X_ACTION_MINIMIZE,
+ ECORE_X_ACTION_SHADE,
+ ECORE_X_ACTION_STICK,
+ ECORE_X_ACTION_MAXIMIZE_HORZ,
+ ECORE_X_ACTION_MAXIMIZE_VERT,
+ ECORE_X_ACTION_FULLSCREEN,
+ ECORE_X_ACTION_CHANGE_DESKTOP,
+ ECORE_X_ACTION_CLOSE,
+ ECORE_X_ACTION_ABOVE,
+ ECORE_X_ACTION_BELOW
+} Ecore_X_Action;
+
+typedef enum _Ecore_X_Window_Configure_Mask
+{
+ ECORE_X_WINDOW_CONFIGURE_MASK_X = (1 << 0),
+ ECORE_X_WINDOW_CONFIGURE_MASK_Y = (1 << 1),
+ ECORE_X_WINDOW_CONFIGURE_MASK_W = (1 << 2),
+ ECORE_X_WINDOW_CONFIGURE_MASK_H = (1 << 3),
+ ECORE_X_WINDOW_CONFIGURE_MASK_BORDER_WIDTH = (1 << 4),
+ ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING = (1 << 5),
+ ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE = (1 << 6)
+} Ecore_X_Window_Configure_Mask;
+
+typedef enum _Ecore_X_Virtual_Keyboard_State
+{
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN = 0,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_ON,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_IP,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_URL,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD,
+ ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME
+} Ecore_X_Virtual_Keyboard_State;
+
+typedef enum _Ecore_X_Illume_Mode
+{
+ ECORE_X_ILLUME_MODE_UNKNOWN = 0,
+ ECORE_X_ILLUME_MODE_SINGLE,
+ ECORE_X_ILLUME_MODE_DUAL_TOP,
+ ECORE_X_ILLUME_MODE_DUAL_LEFT
+} Ecore_X_Illume_Mode;
+
+typedef enum _Ecore_X_Illume_Quickpanel_State
+{
+ ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN = 0,
+ ECORE_X_ILLUME_QUICKPANEL_STATE_OFF,
+ ECORE_X_ILLUME_QUICKPANEL_STATE_ON
+} Ecore_X_Illume_Quickpanel_State;
+
+typedef enum _Ecore_X_Illume_Indicator_State
+{
+ ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN = 0,
+ ECORE_X_ILLUME_INDICATOR_STATE_OFF,
+ ECORE_X_ILLUME_INDICATOR_STATE_ON
+} Ecore_X_Illume_Indicator_State;
+
+typedef enum _Ecore_X_Illume_Clipboard_State
+{
+ ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN = 0,
+ ECORE_X_ILLUME_CLIPBOARD_STATE_OFF,
+ ECORE_X_ILLUME_CLIPBOARD_STATE_ON
+} Ecore_X_Illume_Clipboard_State;
+
+typedef enum _Ecore_X_Illume_Indicator_Opacity_Mode
+{
+ ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN = 0,
+ ECORE_X_ILLUME_INDICATOR_OPAQUE,
+ ECORE_X_ILLUME_INDICATOR_TRANSLUCENT,
+ ECORE_X_ILLUME_INDICATOR_TRANSPARENT
+} Ecore_X_Illume_Indicator_Opacity_Mode;
+
+typedef enum _Ecore_X_Illume_Window_State
+{
+ ECORE_X_ILLUME_WINDOW_STATE_NORMAL = 0,
+ ECORE_X_ILLUME_WINDOW_STATE_FLOATING
+} Ecore_X_Illume_Window_State;
+
+/* Window layer constants */
+#define ECORE_X_WINDOW_LAYER_BELOW 2
+#define ECORE_X_WINDOW_LAYER_NORMAL 4
+#define ECORE_X_WINDOW_LAYER_ABOVE 6
+
+/* Property list operations */
+#define ECORE_X_PROP_LIST_REMOVE 0
+#define ECORE_X_PROP_LIST_ADD 1
+#define ECORE_X_PROP_LIST_TOGGLE 2
+
+EAPI int ecore_x_init(const char *name);
+EAPI int ecore_x_shutdown(void);
+EAPI int ecore_x_disconnect(void);
+EAPI Ecore_X_Display *ecore_x_display_get(void);
+EAPI Ecore_X_Connection *ecore_x_connection_get(void);
+EAPI int ecore_x_fd_get(void);
+EAPI Ecore_X_Screen *ecore_x_default_screen_get(void);
+EAPI void ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h);
+EAPI int ecore_x_screen_count_get(void);
+EAPI int ecore_x_screen_index_get(const Ecore_X_Screen *screen);
+EAPI Ecore_X_Screen *ecore_x_screen_get(int index);
+
+EAPI void ecore_x_double_click_time_set(double t);
+EAPI double ecore_x_double_click_time_get(void);
+EAPI void ecore_x_flush(void);
+EAPI void ecore_x_sync(void);
+EAPI void ecore_x_killall(Ecore_X_Window root);
+EAPI void ecore_x_kill(Ecore_X_Window win);
+EAPI int ecore_x_dpi_get(void);
+EAPI Eina_Bool ecore_x_bell(int percent);
+EAPI unsigned int ecore_x_visual_id_get(Ecore_X_Visual visual);
+
+EAPI Ecore_X_Visual ecore_x_default_visual_get(Ecore_X_Display *disp, Ecore_X_Screen *screen);
+EAPI Ecore_X_Colormap ecore_x_default_colormap_get(Ecore_X_Display *disp, Ecore_X_Screen *screen);
+EAPI int ecore_x_default_depth_get(Ecore_X_Display *disp, Ecore_X_Screen *screen);
+
+EAPI Ecore_X_Time ecore_x_current_time_get(void);
+
+EAPI void ecore_x_error_handler_set(void (*func)(void *data), const void *data);
+EAPI void ecore_x_io_error_handler_set(void (*func)(void *data), const void *data);
+EAPI int ecore_x_error_request_get(void);
+EAPI int ecore_x_error_code_get(void);
+EAPI Ecore_X_ID ecore_x_error_resource_id_get(void);
+
+EAPI void ecore_x_event_mask_set(Ecore_X_Window w, Ecore_X_Event_Mask mask);
+EAPI void ecore_x_event_mask_unset(Ecore_X_Window w, Ecore_X_Event_Mask mask);
+
+EAPI Eina_Bool ecore_x_selection_notify_send(Ecore_X_Window requestor, Ecore_X_Atom selection, Ecore_X_Atom target, Ecore_X_Atom property, Ecore_X_Time time);
+EAPI Eina_Bool ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size);
+EAPI Eina_Bool ecore_x_selection_primary_clear(void);
+EAPI Eina_Bool ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size);
+EAPI Eina_Bool ecore_x_selection_secondary_clear(void);
+EAPI Eina_Bool ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size);
+EAPI Eina_Bool ecore_x_selection_xdnd_clear(void);
+EAPI Eina_Bool ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size);
+EAPI Eina_Bool ecore_x_selection_clipboard_clear(void);
+EAPI void ecore_x_selection_primary_request(Ecore_X_Window w, const char *target);
+EAPI void ecore_x_selection_secondary_request(Ecore_X_Window w, const char *target);
+EAPI void ecore_x_selection_xdnd_request(Ecore_X_Window w, const char *target);
+EAPI void ecore_x_selection_clipboard_request(Ecore_X_Window w, const char *target);
+EAPI Eina_Bool ecore_x_selection_convert(Ecore_X_Atom selection, Ecore_X_Atom target, void **data_ret, int *len, Ecore_X_Atom *targprop, int *targsize);
+EAPI void ecore_x_selection_converter_add(char *target, Eina_Bool (*func)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *, int *));
+EAPI void ecore_x_selection_converter_atom_add(Ecore_X_Atom target, Eina_Bool (*func)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *tprop, int *tsize));
+EAPI void ecore_x_selection_converter_del(char *target);
+EAPI void ecore_x_selection_converter_atom_del(Ecore_X_Atom target);
+EAPI void ecore_x_selection_parser_add(const char *target, void *(*func)(const char *target, void *data, int size, int format));
+EAPI void ecore_x_selection_parser_del(const char *target);
+EAPI void ecore_x_selection_owner_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Time tm);
+EAPI Ecore_X_Window ecore_x_selection_owner_get(Ecore_X_Atom atom);
+EAPI Eina_Bool ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *targprop, int *s); /** @since 1.8 */
+
+EAPI void ecore_x_dnd_aware_set(Ecore_X_Window win, Eina_Bool on);
+EAPI int ecore_x_dnd_version_get(Ecore_X_Window win);
+EAPI Eina_Bool ecore_x_dnd_type_isset(Ecore_X_Window win, const char *type);
+EAPI void ecore_x_dnd_type_set(Ecore_X_Window win, const char *type, Eina_Bool on);
+EAPI void ecore_x_dnd_types_set(Ecore_X_Window win, const char **types, unsigned int num_types);
+EAPI void ecore_x_dnd_actions_set(Ecore_X_Window win, Ecore_X_Atom *actions, unsigned int num_actions);
+EAPI Eina_Bool ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size);
+EAPI Eina_Bool ecore_x_dnd_drop(void);
+EAPI void ecore_x_dnd_send_status(Eina_Bool will_accept, Eina_Bool suppress, Ecore_X_Rectangle rectangle, Ecore_X_Atom action);
+EAPI void ecore_x_dnd_send_finished(void);
+EAPI void ecore_x_dnd_source_action_set(Ecore_X_Atom action);
+EAPI Ecore_X_Atom ecore_x_dnd_source_action_get(void);
+EAPI void ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data), const void *data);
+
+EAPI Ecore_X_Window ecore_x_window_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_x_window_override_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI int ecore_x_window_argb_get(Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_x_window_manager_argb_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_x_window_argb_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_x_window_override_argb_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI Ecore_X_Window ecore_x_window_input_new(Ecore_X_Window parent, int x, int y, int w, int h);
+EAPI void ecore_x_window_configure(Ecore_X_Window win, Ecore_X_Window_Configure_Mask mask, int x, int y, int w, int h, int border_width, Ecore_X_Window sibling, int stack_mode);
+EAPI void ecore_x_window_cursor_set(Ecore_X_Window win, Ecore_X_Cursor c);
+EAPI void ecore_x_window_free(Ecore_X_Window win);
+EAPI void ecore_x_window_ignore_set(Ecore_X_Window win, int ignore);
+EAPI Ecore_X_Window *ecore_x_window_ignore_list(int *num);
+
+EAPI void ecore_x_window_delete_request_send(Ecore_X_Window win);
+EAPI void ecore_x_window_show(Ecore_X_Window win);
+EAPI void ecore_x_window_hide(Ecore_X_Window win);
+EAPI void ecore_x_window_move(Ecore_X_Window win, int x, int y);
+EAPI void ecore_x_window_resize(Ecore_X_Window win, int w, int h);
+EAPI void ecore_x_window_move_resize(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_focus(Ecore_X_Window win);
+EAPI void ecore_x_window_focus_at_time(Ecore_X_Window win, Ecore_X_Time t);
+EAPI Ecore_X_Window ecore_x_window_focus_get(void);
+EAPI void ecore_x_window_raise(Ecore_X_Window win);
+EAPI void ecore_x_window_lower(Ecore_X_Window win);
+EAPI void ecore_x_window_reparent(Ecore_X_Window win, Ecore_X_Window new_parent, int x, int y);
+EAPI void ecore_x_window_size_get(Ecore_X_Window win, int *w, int *h);
+EAPI void ecore_x_window_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h);
+EAPI int ecore_x_window_border_width_get(Ecore_X_Window win);
+EAPI void ecore_x_window_border_width_set(Ecore_X_Window win, int width);
+EAPI int ecore_x_window_depth_get(Ecore_X_Window win);
+EAPI void ecore_x_window_cursor_show(Ecore_X_Window win, Eina_Bool show);
+EAPI void ecore_x_window_defaults_set(Ecore_X_Window win);
+EAPI int ecore_x_window_visible_get(Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y, Ecore_X_Window *skip, int skip_num);
+EAPI Ecore_X_Window ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win);
+EAPI void ecore_x_window_shadow_tree_flush(void);
+EAPI Ecore_X_Window ecore_x_window_root_get(Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_x_window_at_xy_get(int x, int y);
+EAPI Ecore_X_Window ecore_x_window_at_xy_with_skip_get(int x, int y, Ecore_X_Window *skip, int skip_num);
+EAPI Ecore_X_Window ecore_x_window_at_xy_begin_get(Ecore_X_Window begin, int x, int y);
+EAPI Ecore_X_Window ecore_x_window_parent_get(Ecore_X_Window win);
+
+EAPI void ecore_x_window_background_color_set(Ecore_X_Window win, unsigned short r, unsigned short g, unsigned short b);
+EAPI void ecore_x_window_gravity_set(Ecore_X_Window win, Ecore_X_Gravity grav);
+EAPI void ecore_x_window_pixel_gravity_set(Ecore_X_Window win, Ecore_X_Gravity grav);
+EAPI void ecore_x_window_pixmap_set(Ecore_X_Window win, Ecore_X_Pixmap pmap);
+EAPI void ecore_x_window_area_clear(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_area_expose(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_override_set(Ecore_X_Window win, Eina_Bool override);
+
+EAPI void ecore_x_window_prop_card32_set(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int *val, unsigned int num);
+EAPI int ecore_x_window_prop_card32_get(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int *val, unsigned int len);
+EAPI int ecore_x_window_prop_card32_list_get(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int **plst);
+
+EAPI void ecore_x_window_prop_xid_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID *lst, unsigned int num);
+EAPI int ecore_x_window_prop_xid_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID *lst, unsigned int len);
+EAPI int ecore_x_window_prop_xid_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID **plst);
+EAPI void ecore_x_window_prop_xid_list_change(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID item, int op);
+EAPI void ecore_x_window_prop_atom_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom *val, unsigned int num);
+EAPI int ecore_x_window_prop_atom_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom *val, unsigned int len);
+EAPI int ecore_x_window_prop_atom_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom **plst);
+EAPI void ecore_x_window_prop_atom_list_change(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom item, int op);
+EAPI void ecore_x_window_prop_window_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *val, unsigned int num);
+EAPI int ecore_x_window_prop_window_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *val, unsigned int len);
+EAPI int ecore_x_window_prop_window_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window **plst);
+
+EAPI Ecore_X_Atom ecore_x_window_prop_any_type(void);
+EAPI void ecore_x_window_prop_property_set(Ecore_X_Window win, Ecore_X_Atom type, Ecore_X_Atom format, int size, void *data, int number);
+EAPI int ecore_x_window_prop_property_get(Ecore_X_Window win, Ecore_X_Atom property, Ecore_X_Atom type, int size, unsigned char **data, int *num);
+EAPI void ecore_x_window_prop_property_del(Ecore_X_Window win, Ecore_X_Atom property);
+EAPI Ecore_X_Atom *ecore_x_window_prop_list(Ecore_X_Window win, int *num_ret);
+EAPI void ecore_x_window_prop_string_set(Ecore_X_Window win, Ecore_X_Atom type, const char *str);
+EAPI char *ecore_x_window_prop_string_get(Ecore_X_Window win, Ecore_X_Atom type);
+EAPI Eina_Bool ecore_x_window_prop_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol);
+EAPI Ecore_X_WM_Protocol *ecore_x_window_prop_protocol_list_get(Ecore_X_Window win, int *num_ret);
+
+EAPI void ecore_x_window_shape_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask);
+EAPI void ecore_x_window_shape_window_set(Ecore_X_Window win, Ecore_X_Window shape_win);
+EAPI void ecore_x_window_shape_window_set_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y);
+EAPI void ecore_x_window_shape_rectangle_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_rectangles_set(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num);
+EAPI void ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num);
+EAPI void ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y);
+EAPI void ecore_x_window_shape_input_window_set(Ecore_X_Window win, Ecore_X_Window shape_win);
+EAPI void ecore_x_window_shape_window_add(Ecore_X_Window win, Ecore_X_Window shape_win);
+EAPI void ecore_x_window_shape_window_add_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y);
+EAPI void ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y);
+EAPI void ecore_x_window_shape_rectangle_add(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_rectangle_clip(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_window_shape_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num);
+EAPI void ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num);
+EAPI Ecore_X_Rectangle *ecore_x_window_shape_rectangles_get(Ecore_X_Window win, int *num_ret);
+EAPI Ecore_X_Rectangle *ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win, int *num_ret);
+EAPI void ecore_x_window_shape_events_select(Ecore_X_Window win, Eina_Bool on);
+EAPI void ecore_x_window_shape_input_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask);
+
+EAPI Ecore_X_Pixmap ecore_x_pixmap_new(Ecore_X_Window win, int w, int h, int dep);
+EAPI void ecore_x_pixmap_free(Ecore_X_Pixmap pmap);
+EAPI void ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, Ecore_X_Drawable dest, Ecore_X_GC gc, int sx, int sy, int w, int h, int dx, int dy);
+EAPI void ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, int *x, int *y, int *w, int *h);
+EAPI int ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap);
+
+EAPI Ecore_X_GC ecore_x_gc_new(Ecore_X_Drawable draw, Ecore_X_GC_Value_Mask value_mask, const unsigned int *value_list);
+EAPI void ecore_x_gc_free(Ecore_X_GC gc);
+EAPI void ecore_x_gc_foreground_set(Ecore_X_GC gc, unsigned long foreground);
+EAPI void ecore_x_gc_background_set(Ecore_X_GC gc, unsigned long background);
+
+EAPI Eina_Bool ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type, Ecore_X_Event_Mask mask, long d0, long d1, long d2, long d3, long d4);
+EAPI Eina_Bool ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, const void *data, int len);
+EAPI Eina_Bool ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y);
+EAPI Eina_Bool ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b);
+EAPI Eina_Bool ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b);
+EAPI Eina_Bool ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y);
+EAPI Eina_Bool ecore_x_mouse_out_send(Ecore_X_Window win, int x, int y);
+
+EAPI void ecore_x_drawable_geometry_get(Ecore_X_Drawable d, int *x, int *y, int *w, int *h);
+EAPI int ecore_x_drawable_border_width_get(Ecore_X_Drawable d);
+EAPI int ecore_x_drawable_depth_get(Ecore_X_Drawable d);
+EAPI void ecore_x_drawable_rectangle_fill(Ecore_X_Drawable d, Ecore_X_GC gc, int x, int y, int width, int height);
+
+EAPI Eina_Bool ecore_x_cursor_color_supported_get(void);
+EAPI Ecore_X_Cursor ecore_x_cursor_new(Ecore_X_Window win, int *pixels, int w, int h, int hot_x, int hot_y);
+EAPI void ecore_x_cursor_free(Ecore_X_Cursor c);
+EAPI Ecore_X_Cursor ecore_x_cursor_shape_get(int shape);
+EAPI void ecore_x_cursor_size_set(int size);
+EAPI int ecore_x_cursor_size_get(void);
+
+/* FIXME: these funcs need categorising */
+EAPI Ecore_X_Window *ecore_x_window_root_list(int *num_ret);
+EAPI Ecore_X_Window ecore_x_window_root_first_get(void);
+EAPI Eina_Bool ecore_x_window_manage(Ecore_X_Window win);
+EAPI void ecore_x_window_container_manage(Ecore_X_Window win);
+EAPI void ecore_x_window_client_manage(Ecore_X_Window win);
+EAPI void ecore_x_window_sniff(Ecore_X_Window win);
+EAPI void ecore_x_window_client_sniff(Ecore_X_Window win);
+
+EAPI Ecore_X_Atom ecore_x_atom_get(const char *name);
+EAPI void ecore_x_atoms_get(const char **names, int num, Ecore_X_Atom *atoms);
+EAPI char *ecore_x_atom_name_get(Ecore_X_Atom atom);
+
+EAPI void ecore_x_icccm_init(void);
+EAPI void ecore_x_icccm_state_set(Ecore_X_Window win, Ecore_X_Window_State_Hint state);
+EAPI Ecore_X_Window_State_Hint ecore_x_icccm_state_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_delete_window_send(Ecore_X_Window win, Ecore_X_Time t);
+EAPI void ecore_x_icccm_take_focus_send(Ecore_X_Window win, Ecore_X_Time t);
+EAPI void ecore_x_icccm_save_yourself_send(Ecore_X_Window win, Ecore_X_Time t);
+EAPI void ecore_x_icccm_move_resize_send(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI void ecore_x_icccm_hints_set(Ecore_X_Window win, Eina_Bool accepts_focus, Ecore_X_Window_State_Hint initial_state, Ecore_X_Pixmap icon_pixmap, Ecore_X_Pixmap icon_mask, Ecore_X_Window icon_window, Ecore_X_Window window_group, Eina_Bool is_urgent);
+EAPI Eina_Bool ecore_x_icccm_hints_get(Ecore_X_Window win, Eina_Bool *accepts_focus, Ecore_X_Window_State_Hint *initial_state, Ecore_X_Pixmap *icon_pixmap, Ecore_X_Pixmap *icon_mask, Ecore_X_Window *icon_window, Ecore_X_Window *window_group, Eina_Bool *is_urgent);
+EAPI void ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, Eina_Bool request_pos, Ecore_X_Gravity gravity, int min_w, int min_h, int max_w, int max_h, int base_w, int base_h, int step_x, int step_y, double min_aspect, double max_aspect);
+EAPI Eina_Bool ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, Eina_Bool *request_pos, Ecore_X_Gravity *gravity, int *min_w, int *min_h, int *max_w, int *max_h, int *base_w, int *base_h, int *step_x, int *step_y, double *min_aspect, double *max_aspect);
+EAPI void ecore_x_icccm_title_set(Ecore_X_Window win, const char *t);
+EAPI char *ecore_x_icccm_title_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win, Ecore_X_Atom *protos, int num);
+EAPI void ecore_x_icccm_protocol_set(Ecore_X_Window win, Ecore_X_WM_Protocol protocol, Eina_Bool on);
+EAPI Eina_Bool ecore_x_icccm_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol);
+EAPI void ecore_x_icccm_name_class_set(Ecore_X_Window win, const char *n, const char *c);
+EAPI void ecore_x_icccm_name_class_get(Ecore_X_Window win, char **n, char **c);
+EAPI char *ecore_x_icccm_client_machine_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_command_set(Ecore_X_Window win, int argc, char **argv);
+EAPI void ecore_x_icccm_command_get(Ecore_X_Window win, int *argc, char ***argv);
+EAPI char *ecore_x_icccm_icon_name_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_icon_name_set(Ecore_X_Window win, const char *t);
+EAPI void ecore_x_icccm_colormap_window_set(Ecore_X_Window win, Ecore_X_Window subwin);
+EAPI void ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, Ecore_X_Window subwin);
+EAPI void ecore_x_icccm_transient_for_set(Ecore_X_Window win, Ecore_X_Window forwin);
+EAPI void ecore_x_icccm_transient_for_unset(Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_x_icccm_transient_for_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_window_role_set(Ecore_X_Window win, const char *role);
+EAPI char *ecore_x_icccm_window_role_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_client_leader_set(Ecore_X_Window win, Ecore_X_Window l);
+EAPI Ecore_X_Window ecore_x_icccm_client_leader_get(Ecore_X_Window win);
+EAPI void ecore_x_icccm_iconic_request_send(Ecore_X_Window win, Ecore_X_Window root);
+
+typedef enum _Ecore_X_MWM_Hint_Func
+{
+ ECORE_X_MWM_HINT_FUNC_ALL = (1 << 0),
+ ECORE_X_MWM_HINT_FUNC_RESIZE = (1 << 1),
+ ECORE_X_MWM_HINT_FUNC_MOVE = (1 << 2),
+ ECORE_X_MWM_HINT_FUNC_MINIMIZE = (1 << 3),
+ ECORE_X_MWM_HINT_FUNC_MAXIMIZE = (1 << 4),
+ ECORE_X_MWM_HINT_FUNC_CLOSE = (1 << 5)
+} Ecore_X_MWM_Hint_Func;
+
+typedef enum _Ecore_X_MWM_Hint_Decor
+{
+ ECORE_X_MWM_HINT_DECOR_ALL = (1 << 0),
+ ECORE_X_MWM_HINT_DECOR_BORDER = (1 << 1),
+ ECORE_X_MWM_HINT_DECOR_RESIZEH = (1 << 2),
+ ECORE_X_MWM_HINT_DECOR_TITLE = (1 << 3),
+ ECORE_X_MWM_HINT_DECOR_MENU = (1 << 4),
+ ECORE_X_MWM_HINT_DECOR_MINIMIZE = (1 << 5),
+ ECORE_X_MWM_HINT_DECOR_MAXIMIZE = (1 << 6)
+} Ecore_X_MWM_Hint_Decor;
+
+typedef enum _Ecore_X_MWM_Hint_Input
+{
+ ECORE_X_MWM_HINT_INPUT_MODELESS = 0,
+ ECORE_X_MWM_HINT_INPUT_PRIMARY_APPLICATION_MODAL = 1,
+ ECORE_X_MWM_HINT_INPUT_SYSTEM_MODAL = 2,
+ ECORE_X_MWM_HINT_INPUT_FULL_APPLICATION_MODAL = 3
+} Ecore_X_MWM_Hint_Input;
+
+EAPI Eina_Bool ecore_x_mwm_hints_get(Ecore_X_Window win, Ecore_X_MWM_Hint_Func *fhint, Ecore_X_MWM_Hint_Decor *dhint, Ecore_X_MWM_Hint_Input *ihint);
+EAPI void ecore_x_mwm_borderless_set(Ecore_X_Window win, Eina_Bool borderless);
+
+/* netwm */
+EAPI void ecore_x_netwm_init(void);
+EAPI void ecore_x_netwm_shutdown(void);
+EAPI void ecore_x_netwm_wm_identify(Ecore_X_Window root, Ecore_X_Window check, const char *wm_name);
+EAPI void ecore_x_netwm_supported_set(Ecore_X_Window root, Ecore_X_Atom *supported, int num);
+EAPI Eina_Bool ecore_x_netwm_supported_get(Ecore_X_Window root, Ecore_X_Atom **supported, int *num);
+EAPI void ecore_x_netwm_desk_count_set(Ecore_X_Window root, unsigned int n_desks);
+EAPI void ecore_x_netwm_desk_roots_set(Ecore_X_Window root, Ecore_X_Window *vroots, unsigned int n_desks);
+EAPI void ecore_x_netwm_desk_names_set(Ecore_X_Window root, const char **names, unsigned int n_desks);
+EAPI void ecore_x_netwm_desk_size_set(Ecore_X_Window root, unsigned int width, unsigned int height);
+EAPI void ecore_x_netwm_desk_workareas_set(Ecore_X_Window root, unsigned int *areas, unsigned int n_desks);
+EAPI unsigned int *ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks);
+EAPI void ecore_x_netwm_desk_current_set(Ecore_X_Window root, unsigned int desk);
+EAPI void ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, unsigned int *origins, unsigned int n_desks);
+EAPI void ecore_x_netwm_desk_layout_set(Ecore_X_Window root, int orientation, int columns, int rows, int starting_corner);
+EAPI void ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, Eina_Bool on);
+EAPI void ecore_x_netwm_client_list_set(Ecore_X_Window root, Ecore_X_Window *p_clients, unsigned int n_clients);
+EAPI void ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, Ecore_X_Window *p_clients, unsigned int n_clients);
+EAPI void ecore_x_netwm_client_active_set(Ecore_X_Window root, Ecore_X_Window win);
+EAPI void ecore_x_netwm_client_active_request(Ecore_X_Window root, Ecore_X_Window win, int type, Ecore_X_Window current_win);
+EAPI void ecore_x_netwm_name_set(Ecore_X_Window win, const char *name);
+EAPI int ecore_x_netwm_name_get(Ecore_X_Window win, char **name);
+EAPI void ecore_x_netwm_startup_id_set(Ecore_X_Window win, const char *id);
+EAPI int ecore_x_netwm_startup_id_get(Ecore_X_Window win, char **id);
+EAPI void ecore_x_netwm_visible_name_set(Ecore_X_Window win, const char *name);
+EAPI int ecore_x_netwm_visible_name_get(Ecore_X_Window win, char **name);
+EAPI void ecore_x_netwm_icon_name_set(Ecore_X_Window win, const char *name);
+EAPI int ecore_x_netwm_icon_name_get(Ecore_X_Window win, char **name);
+EAPI void ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win, const char *name);
+EAPI int ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, char **name);
+EAPI void ecore_x_netwm_desktop_set(Ecore_X_Window win, unsigned int desk);
+EAPI Eina_Bool ecore_x_netwm_desktop_get(Ecore_X_Window win, unsigned int *desk);
+EAPI void ecore_x_netwm_strut_set(Ecore_X_Window win, int left, int right, int top, int bottom);
+EAPI Eina_Bool ecore_x_netwm_strut_get(Ecore_X_Window win, int *left, int *right, int *top, int *bottom);
+EAPI void ecore_x_netwm_strut_partial_set(Ecore_X_Window win, int left, int right, int top, int bottom, int left_start_y, int left_end_y, int right_start_y, int right_end_y, int top_start_x, int top_end_x, int bottom_start_x, int bottom_end_x);
+EAPI Eina_Bool ecore_x_netwm_strut_partial_get(Ecore_X_Window win, int *left, int *right, int *top, int *bottom, int *left_start_y, int *left_end_y, int *right_start_y, int *right_end_y, int *top_start_x, int *top_end_x, int *bottom_start_x, int *bottom_end_x);
+
+EAPI void ecore_x_netwm_icons_set(Ecore_X_Window win, Ecore_X_Icon *icon, int num);
+
+EAPI Eina_Bool ecore_x_netwm_icons_get(Ecore_X_Window win, Ecore_X_Icon **icon, int *num);
+EAPI void ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, int x, int y, int width, int height);
+EAPI Eina_Bool ecore_x_netwm_icon_geometry_get(Ecore_X_Window win, int *x, int *y, int *width, int *height);
+EAPI void ecore_x_netwm_pid_set(Ecore_X_Window win, int pid);
+EAPI Eina_Bool ecore_x_netwm_pid_get(Ecore_X_Window win, int *pid);
+EAPI void ecore_x_netwm_handled_icons_set(Ecore_X_Window win);
+EAPI Eina_Bool ecore_x_netwm_handled_icons_get(Ecore_X_Window win);
+EAPI void ecore_x_netwm_user_time_set(Ecore_X_Window win, unsigned int time);
+EAPI Eina_Bool ecore_x_netwm_user_time_get(Ecore_X_Window win, unsigned int *time);
+EAPI void ecore_x_netwm_window_state_set(Ecore_X_Window win, Ecore_X_Window_State *state, unsigned int num);
+EAPI Eina_Bool ecore_x_netwm_window_state_get(Ecore_X_Window win, Ecore_X_Window_State **state, unsigned int *num);
+EAPI void ecore_x_netwm_window_type_set(Ecore_X_Window win, Ecore_X_Window_Type type);
+EAPI Eina_Bool ecore_x_netwm_window_type_get(Ecore_X_Window win, Ecore_X_Window_Type *type);
+EAPI int ecore_x_netwm_window_types_get(Ecore_X_Window win, Ecore_X_Window_Type **types);
+EAPI Eina_Bool ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, Ecore_X_Action action);
+EAPI void ecore_x_netwm_allowed_action_set(Ecore_X_Window win, Ecore_X_Action *action, unsigned int num);
+EAPI Eina_Bool ecore_x_netwm_allowed_action_get(Ecore_X_Window win, Ecore_X_Action **action, unsigned int *num);
+EAPI void ecore_x_netwm_opacity_set(Ecore_X_Window win, unsigned int opacity);
+EAPI Eina_Bool ecore_x_netwm_opacity_get(Ecore_X_Window win, unsigned int *opacity);
+EAPI void ecore_x_netwm_frame_size_set(Ecore_X_Window win, int fl, int fr, int ft, int fb);
+EAPI Eina_Bool ecore_x_netwm_frame_size_get(Ecore_X_Window win, int *fl, int *fr, int *ft, int *fb);
+EAPI Eina_Bool ecore_x_netwm_sync_counter_get(Ecore_X_Window win, Ecore_X_Sync_Counter *counter);
+EAPI void ecore_x_netwm_ping_send(Ecore_X_Window win);
+EAPI void ecore_x_netwm_sync_request_send(Ecore_X_Window win, unsigned int serial);
+EAPI void ecore_x_netwm_state_request_send(Ecore_X_Window win, Ecore_X_Window root, Ecore_X_Window_State s1, Ecore_X_Window_State s2, Eina_Bool set);
+EAPI void ecore_x_netwm_desktop_request_send(Ecore_X_Window win, Ecore_X_Window root, unsigned int desktop);
+EAPI void ecore_x_netwm_moveresize_request_send(Ecore_X_Window win, int x, int y, Ecore_X_Netwm_Direction direction, unsigned int button);
+
+EAPI void ecore_x_e_init(void);
+EAPI void ecore_x_e_frame_size_set(Ecore_X_Window win, int fl, int fr, int ft, int fb);
+EAPI void ecore_x_e_virtual_keyboard_set(Ecore_X_Window win, unsigned int is_keyboard);
+EAPI Eina_Bool ecore_x_e_virtual_keyboard_get(Ecore_X_Window win);
+EAPI void ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win, Ecore_X_Virtual_Keyboard_State state);
+EAPI Ecore_X_Virtual_Keyboard_State ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win);
+EAPI void ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win, Ecore_X_Virtual_Keyboard_State state);
+
+/* Illume functions */
+EAPI void ecore_x_e_illume_zone_set(Ecore_X_Window win, Ecore_X_Window zone);
+EAPI Ecore_X_Window ecore_x_e_illume_zone_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_zone_list_set(Ecore_X_Window win, Ecore_X_Window *zones, unsigned int n_zones);
+EAPI void ecore_x_e_illume_conformant_set(Ecore_X_Window win, unsigned int is_conformant);
+EAPI Eina_Bool ecore_x_e_illume_conformant_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_mode_set(Ecore_X_Window win, Ecore_X_Illume_Mode mode);
+EAPI Ecore_X_Illume_Mode ecore_x_e_illume_mode_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_mode_send(Ecore_X_Window win, Ecore_X_Illume_Mode mode);
+EAPI void ecore_x_e_illume_focus_back_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_focus_forward_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_focus_home_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_close_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_home_new_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_home_del_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_next_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_read_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_up_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_access_action_down_send(Ecore_X_Window win);
+
+EAPI void ecore_x_e_illume_drag_set(Ecore_X_Window win, unsigned int drag);
+EAPI Eina_Bool ecore_x_e_illume_drag_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_drag_locked_set(Ecore_X_Window win, unsigned int is_locked);
+EAPI Eina_Bool ecore_x_e_illume_drag_locked_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_drag_start_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_drag_end_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI Eina_Bool ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h);
+EAPI void ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI Eina_Bool ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h);
+EAPI void ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI Eina_Bool ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h);
+EAPI void ecore_x_e_illume_quickpanel_set(Ecore_X_Window win, unsigned int is_quickpanel);
+EAPI Eina_Bool ecore_x_e_illume_quickpanel_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win, Ecore_X_Illume_Quickpanel_State state);
+EAPI Ecore_X_Illume_Quickpanel_State ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win, Ecore_X_Illume_Quickpanel_State state);
+EAPI void ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win, unsigned int priority);
+EAPI int ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win, unsigned int priority);
+EAPI int ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win, unsigned int zone);
+EAPI int ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_zone_request_send(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win);
+
+EAPI void ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win, Ecore_X_Illume_Clipboard_State state);
+
+EAPI Ecore_X_Illume_Clipboard_State ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win);
+
+EAPI void ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win, int x, int y, int w, int h);
+EAPI Eina_Bool ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h);
+EAPI void ecore_x_e_comp_sync_counter_set(Ecore_X_Window win, Ecore_X_Sync_Counter counter);
+EAPI Ecore_X_Sync_Counter ecore_x_e_comp_sync_counter_get(Ecore_X_Window win);
+EAPI void ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root, Ecore_X_Window win);
+EAPI void ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root, Ecore_X_Window win, int w, int h);
+EAPI void ecore_x_e_comp_sync_supported_set(Ecore_X_Window root, Eina_Bool enabled);
+EAPI Eina_Bool ecore_x_e_comp_sync_supported_get(Ecore_X_Window root);
+EAPI void ecore_x_e_comp_sync_begin_send(Ecore_X_Window win);
+EAPI void ecore_x_e_comp_sync_end_send(Ecore_X_Window win);
+EAPI void ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win);
+
+EAPI void ecore_x_e_comp_flush_send(Ecore_X_Window win);
+EAPI void ecore_x_e_comp_dump_send(Ecore_X_Window win);
+EAPI void ecore_x_e_comp_pixmap_set(Ecore_X_Window win, Ecore_X_Pixmap pixmap);
+EAPI Ecore_X_Pixmap ecore_x_e_comp_pixmap_get(Ecore_X_Window win);
+
+EAPI char *ecore_x_e_window_profile_get(Ecore_X_Window win);
+EAPI void ecore_x_e_window_profile_set(Ecore_X_Window win, const char *profile);
+EAPI void ecore_x_e_window_profile_list_set(Ecore_X_Window win, const char **profiles, unsigned int num_profiles);
+EAPI Eina_Bool ecore_x_e_window_profile_list_get(Ecore_X_Window win, const char ***profiles, int *ret_num);
+
+EAPI Ecore_X_Sync_Alarm ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter);
+EAPI Eina_Bool ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm);
+EAPI Eina_Bool ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter, unsigned int *val);
+EAPI Ecore_X_Sync_Counter ecore_x_sync_counter_new(int val);
+EAPI void ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter);
+EAPI void ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter, int by);
+EAPI void ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter, int val);
+
+EAPI void ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter, int val);
+EAPI void ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter, int val_hi, unsigned int val_lo);
+EAPI Eina_Bool ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter, int *val_hi, unsigned int *val_lo);
+
+EAPI int ecore_x_xinerama_screen_count_get(void);
+EAPI Eina_Bool ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, int *w, int *h);
+
+EAPI Eina_Bool ecore_x_screensaver_event_available_get(void);
+EAPI int ecore_x_screensaver_idle_time_get(void);
+EAPI void ecore_x_screensaver_set(int timeout, int interval, int prefer_blanking, int allow_exposures);
+EAPI void ecore_x_screensaver_timeout_set(int timeout);
+EAPI int ecore_x_screensaver_timeout_get(void);
+EAPI void ecore_x_screensaver_blank_set(int timeout);
+EAPI int ecore_x_screensaver_blank_get(void);
+EAPI void ecore_x_screensaver_expose_set(int timeout);
+EAPI int ecore_x_screensaver_expose_get(void);
+EAPI void ecore_x_screensaver_interval_set(int timeout);
+EAPI int ecore_x_screensaver_interval_get(void);
+EAPI void ecore_x_screensaver_event_listen_set(Eina_Bool on);
+EAPI Eina_Bool ecore_x_screensaver_custom_blanking_enable(void); /** @since 1.7 */
+EAPI Eina_Bool ecore_x_screensaver_custom_blanking_disable(void); /** @since 1.7 */
+
+/* FIXME: these funcs need categorising */
+
+typedef struct _Ecore_X_Window_Attributes
+{
+ Ecore_X_Window root;
+ int x, y, w, h;
+ int border;
+ int depth;
+ Eina_Bool visible : 1;
+ Eina_Bool viewable : 1;
+ Eina_Bool override : 1;
+ Eina_Bool input_only : 1;
+ Eina_Bool save_under : 1;
+ struct
+ {
+ Ecore_X_Event_Mask mine;
+ Ecore_X_Event_Mask all;
+ Ecore_X_Event_Mask no_propagate;
+ } event_mask;
+ Ecore_X_Gravity window_gravity;
+ Ecore_X_Gravity pixel_gravity;
+ Ecore_X_Colormap colormap;
+ Ecore_X_Visual visual;
+ /* FIXME: missing
+ * int map_installed;
+ * Screen *screen;
+ */
+} Ecore_X_Window_Attributes;
+
+EAPI Eina_Bool ecore_x_window_attributes_get(Ecore_X_Window win, Ecore_X_Window_Attributes *att_ret);
+EAPI void ecore_x_window_save_set_add(Ecore_X_Window win);
+EAPI void ecore_x_window_save_set_del(Ecore_X_Window win);
+EAPI Ecore_X_Window *ecore_x_window_children_get(Ecore_X_Window win, int *num);
+
+EAPI Eina_Bool ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold);
+EAPI Eina_Bool ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold);
+EAPI Eina_Bool ecore_x_pointer_mapping_set(unsigned char *map, int nmap);
+EAPI Eina_Bool ecore_x_pointer_mapping_get(unsigned char *map, int nmap);
+EAPI Eina_Bool ecore_x_pointer_grab(Ecore_X_Window win);
+EAPI Eina_Bool ecore_x_pointer_confine_grab(Ecore_X_Window win);
+EAPI void ecore_x_pointer_ungrab(void);
+EAPI Eina_Bool ecore_x_pointer_warp(Ecore_X_Window win, int x, int y);
+EAPI Eina_Bool ecore_x_keyboard_grab(Ecore_X_Window win);
+EAPI void ecore_x_keyboard_ungrab(void);
+EAPI void ecore_x_grab(void);
+EAPI void ecore_x_ungrab(void);
+EAPI void ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int event_type, void *event), void *data);
+EAPI void ecore_x_window_button_grab(Ecore_X_Window win, int button, Ecore_X_Event_Mask event_mask, int mod, int any_mod);
+EAPI void ecore_x_window_button_ungrab(Ecore_X_Window win, int button, int mod, int any_mod);
+EAPI void ecore_x_window_key_grab(Ecore_X_Window win, const char *key, int mod, int any_mod);
+EAPI void ecore_x_window_key_ungrab(Ecore_X_Window win, const char *key, int mod, int any_mod);
+
+EAPI void ecore_x_focus_reset(void);
+EAPI void ecore_x_events_allow_all(void);
+EAPI void ecore_x_pointer_last_xy_get(int *x, int *y);
+EAPI void ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y);
+
+/* ecore_x_region.c */
+EAPI Ecore_X_XRegion *ecore_x_xregion_new(void);
+EAPI void ecore_x_xregion_free(Ecore_X_XRegion *region);
+EAPI Eina_Bool ecore_x_xregion_set(Ecore_X_XRegion *region, Ecore_X_GC gc);
+EAPI void ecore_x_xregion_translate(Ecore_X_XRegion *region, int x, int y);
+EAPI Eina_Bool ecore_x_xregion_intersect(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2);
+EAPI Eina_Bool ecore_x_xregion_union(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2);
+EAPI Eina_Bool ecore_x_xregion_union_rect(Ecore_X_XRegion *dst, Ecore_X_XRegion *src, Ecore_X_Rectangle *rect);
+EAPI Eina_Bool ecore_x_xregion_subtract(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2);
+EAPI Eina_Bool ecore_x_xregion_is_empty(Ecore_X_XRegion *region);
+EAPI Eina_Bool ecore_x_xregion_is_equal(Ecore_X_XRegion *r1, Ecore_X_XRegion *r2);
+EAPI Eina_Bool ecore_x_xregion_point_contain(Ecore_X_XRegion *region, int x, int y);
+EAPI Eina_Bool ecore_x_xregion_rect_contain(Ecore_X_XRegion *region, Ecore_X_Rectangle *rect);
+
+/* ecore_x_randr.c */
+
+/* The usage of 'Ecore_X_Randr_None' or 'Ecore_X_Randr_Unset'
+ * depends on the context. In most cases 'Ecore_X_Randr_Unset'
+ * can be used, but in some cases -1 is a special value to
+ * functions, thus 'Ecore_X_Randr_None' (=0) must be used.
+ */
+
+typedef short Ecore_X_Randr_Refresh_Rate;
+typedef int Ecore_X_Randr_Crtc_Gamma;
+typedef int Ecore_X_Randr_Signal_Format;
+typedef int Ecore_X_Randr_Signal_Property;
+typedef int Ecore_X_Randr_Connector_Type;
+
+typedef struct _Ecore_X_Randr_Mode_Info
+{
+ Ecore_X_ID xid;
+ unsigned int width;
+ unsigned int height;
+ unsigned long dotClock;
+ unsigned int hSyncStart;
+ unsigned int hSyncEnd;
+ unsigned int hTotal;
+ unsigned int hSkew;
+ unsigned int vSyncStart;
+ unsigned int vSyncEnd;
+ unsigned int vTotal;
+ char *name;
+ unsigned int nameLength;
+ unsigned long modeFlags;
+} Ecore_X_Randr_Mode_Info;
+
+EAPI int ecore_x_randr_version_get(void);
+EAPI Eina_Bool ecore_x_randr_query(void);
+
+/* ecore_x_randr_11.c */
+EAPI Ecore_X_Randr_Orientation ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root);
+EAPI Ecore_X_Randr_Orientation ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root);
+EAPI Eina_Bool ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Orientation orientation);
+EAPI Ecore_X_Randr_Screen_Size_MM *ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, int *num);
+
+/**
+ * @brief get the current set size of a given screen's primary output
+ * @param root window which's primary output will be queried
+ * @param w the current size's width
+ * @param h the current size's height
+ * @param w_mm the current size's width in mm
+ * @param h_mm the current size's height in mm
+ * @param size_index of current set size to be used with ecore_x_randr_primary_output_size_set()
+ */
+EAPI void ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm, int *size_index);
+EAPI Eina_Bool ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, int size_index);
+EAPI Ecore_X_Randr_Refresh_Rate ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root);
+EAPI Ecore_X_Randr_Refresh_Rate *ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, int size_index, int *num);
+EAPI Eina_Bool ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, int size_index, Ecore_X_Randr_Refresh_Rate rate);
+
+/* ecore_x_randr_12.c */
+EAPI void ecore_x_randr_events_select(Ecore_X_Window win, Eina_Bool on);
+
+EAPI void ecore_x_randr_screen_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm);
+EAPI void ecore_x_randr_screen_size_range_get(Ecore_X_Window root, int *wmin, int *hmin, int *wmax, int *hmax);
+EAPI void ecore_x_randr_screen_reset(Ecore_X_Window root);
+EAPI Eina_Bool ecore_x_randr_screen_current_size_set(Ecore_X_Window root, int w, int h, int w_mm, int h_mm);
+EAPI Ecore_X_Randr_Mode_Info **ecore_x_randr_modes_info_get(Ecore_X_Window root, int *num);
+EAPI Ecore_X_Randr_Mode ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info);
+EAPI void ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode);
+EAPI Ecore_X_Randr_Mode_Info *ecore_x_randr_mode_info_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode);
+EAPI void ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info);
+EAPI Ecore_X_Randr_Crtc *ecore_x_randr_crtcs_get(Ecore_X_Window root, int *num);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_outputs_get(Ecore_X_Window root, int *num);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_window_outputs_get(Ecore_X_Window window, int *num);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_current_output_get(Ecore_X_Window window, int *num);
+EAPI Ecore_X_Randr_Crtc *ecore_x_randr_window_crtcs_get(Ecore_X_Window window, int *num);
+EAPI Ecore_X_Randr_Crtc *ecore_x_randr_current_crtc_get(Ecore_X_Window window, int *num);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num);
+EAPI void ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h);
+EAPI void ecore_x_randr_crtc_pos_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y);
+EAPI Eina_Bool ecore_x_randr_crtc_pos_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, int y);
+EAPI Ecore_X_Randr_Mode ecore_x_randr_crtc_mode_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc);
+EAPI Eina_Bool ecore_x_randr_crtc_mode_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, Ecore_X_Randr_Mode mode);
+EAPI void ecore_x_randr_crtc_size_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *w, int *h);
+EAPI Ecore_X_Randr_Refresh_Rate ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Mode mode);
+EAPI Ecore_X_Randr_Orientation ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc);
+EAPI Ecore_X_Randr_Orientation ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc);
+EAPI Eina_Bool ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Orientation orientation);
+EAPI Eina_Bool ecore_x_randr_crtc_clone_set(Ecore_X_Window root, Ecore_X_Randr_Crtc original, Ecore_X_Randr_Crtc clone);
+EAPI Eina_Bool ecore_x_randr_crtc_settings_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, int x, int y, Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orientation);
+EAPI Eina_Bool ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc_r1, Ecore_X_Randr_Crtc crtc_r2, Ecore_X_Randr_Output_Policy policy, Ecore_X_Randr_Relative_Alignment alignment);
+EAPI Eina_Bool ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode);
+EAPI void ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode);
+EAPI Ecore_X_Randr_Mode *ecore_x_randr_output_modes_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num, int *npreferred);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_output_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI Ecore_X_Randr_Crtc *ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI Ecore_X_Randr_Crtc ecore_x_randr_output_crtc_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI char *ecore_x_randr_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *len);
+EAPI int ecore_x_randr_crtc_gamma_ramp_size_get(Ecore_X_Randr_Crtc crtc);
+EAPI Ecore_X_Randr_Crtc_Gamma **ecore_x_randr_crtc_gamma_ramps_get(Ecore_X_Randr_Crtc crtc);
+EAPI Eina_Bool ecore_x_randr_crtc_gamma_ramps_set(Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Crtc_Gamma *red, const Ecore_X_Randr_Crtc_Gamma *green, const Ecore_X_Randr_Crtc_Gamma *blue);
+EAPI Eina_Bool ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, const Ecore_X_Randr_Crtc *not_moved, int nnot_moved, int dx, int dy);
+EAPI Eina_Bool ecore_x_randr_move_crtcs(Ecore_X_Window root, const Ecore_X_Randr_Crtc *crtcs, int ncrtc, int dx, int dy);
+EAPI void ecore_x_randr_mode_size_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode, int *w, int *h);
+EAPI Ecore_X_Randr_Connection_Status ecore_x_randr_output_connection_status_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI void ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w, int *h);
+EAPI Eina_Bool ecore_x_randr_output_crtc_set(Ecore_X_Window root, Ecore_X_Randr_Output output, const Ecore_X_Randr_Crtc crtc);
+
+/* ecore_x_randr_12_edid.c */
+
+/**
+ * @brief Validates the header from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if the header is valid, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Checks whether a display's EDID has a valid checksum.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if the checksum is valid, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded version from raw EDID data.
+ *
+ * The return value has the minor version in the lowest 8 bits, and the major
+ * version in all the rest of the bits. i.e.
+ *
+ * minor = (version & 0x000000ff);
+ * major = (version & 0xffffff00) >> 8;
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded major and minor version encasuplated an int.
+ */
+EAPI int ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded manufacturer from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded manufacturer identifier.
+ */
+EAPI char *ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded name from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded manufacturer identifier.
+ */
+EAPI char *ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded ASCII from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded ASCII display identifier.
+ */
+EAPI char *ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded serial identifier from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded serial identifier.
+ */
+EAPI char *ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the encoded model number from raw EDID data.
+ *
+ * The manufacturer ID table is necessary for a useful description.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded model number.
+ */
+EAPI int ecore_x_randr_edid_model_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the manufacturer serial number from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The encoded serial manufacturer serial number.
+ */
+EAPI int ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the manufacturer model number from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The manufacturer's model number.
+ */
+EAPI int ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Looks up the DPMS support from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if DPMS is supported in some way, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Looks up the DPMS Standby support from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if DPMS Standby is supported, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Looks up the DPMS Suspend support from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if DPMS Suspend is supported, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Looks up the DPMS Off support from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if DPMS Off is supported, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the preferred aspect ratio from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The preferred aspect ratio.
+ */
+EAPI Ecore_X_Randr_Edid_Aspect_Ratio ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the supported aspect ratios from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The supported aspect ratios.
+ */
+EAPI Ecore_X_Randr_Edid_Aspect_Ratio ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the supported colorschemes from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The supported colorschemes.
+ */
+EAPI Ecore_X_Randr_Edid_Display_Colorscheme ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the display type from raw EDID data.
+ *
+ * @param edid The edid structure.
+ * @param edid_length Length of the edid structure.
+ * @return @c EINA_TRUE, if the display is a digital one, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length);
+
+/**
+ * @brief Get the display interface type from raw EDID data.
+ *
+ * @param edid the edid structure
+ * @param edid_length length of the edid structure
+ * @return The interface type.
+ */
+EAPI Ecore_X_Randr_Edid_Display_Interface_Type ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length);
+
+/* ecore_x_randr_12.c */
+
+EAPI Eina_Bool ecore_x_randr_output_backlight_available(void);
+EAPI void ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, double level);
+EAPI double ecore_x_randr_output_backlight_level_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI Eina_Bool ecore_x_randr_output_backlight_level_set(Ecore_X_Window root, Ecore_X_Randr_Output output, double level);
+EAPI Ecore_X_Randr_Output ecore_x_randr_primary_output_get(Ecore_X_Window root);
+EAPI void ecore_x_randr_primary_output_set(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI Ecore_X_Render_Subpixel_Order ecore_x_randr_output_subpixel_order_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI unsigned char *ecore_x_randr_output_edid_get(Ecore_X_Window root, Ecore_X_Randr_Output output, unsigned long *length);
+EAPI Ecore_X_Randr_Output *ecore_x_randr_output_wired_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI Ecore_X_Randr_Output **ecore_x_randr_output_compatibility_list_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI Ecore_X_Randr_Signal_Format *ecore_x_randr_output_signal_formats_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI Eina_Bool ecore_x_randr_output_signal_format_set(Ecore_X_Window root, Ecore_X_Randr_Output output, Ecore_X_Randr_Signal_Format *signal);
+EAPI Ecore_X_Randr_Signal_Property *ecore_x_randr_output_signal_properties_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num);
+EAPI int ecore_x_randr_output_connector_number_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+EAPI Ecore_X_Randr_Connector_Type ecore_x_randr_output_connector_type_get(Ecore_X_Window root, Ecore_X_Randr_Output output);
+/* WTF - these dont exist in ecore-x!!!!
+EAPI Eina_Rectangle *ecore_x_randr_crtc_panning_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h);
+EAPI Eina_Bool ecore_x_randr_crtc_panning_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, const int y, const int w, const int h);
+EAPI Eina_Rectangle *ecore_x_randr_crtc_tracking_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h);
+EAPI Eina_Bool ecore_x_randr_crtc_tracking_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, const int y, const int w, const int h);
+EAPI Eina_Rectangle *ecore_x_randr_crtc_border_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc);
+EAPI Eina_Bool ecore_x_randr_crtc_border_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int left, const int top, const int right, const int bottom);
+*/
+
+/* XRender Support (horrendously incomplete) */
+typedef Ecore_X_ID Ecore_X_Picture;
+
+/* XFixes Extension Support */
+typedef Ecore_X_ID Ecore_X_Region;
+
+typedef enum _Ecore_X_Region_Type
+{
+ ECORE_X_REGION_BOUNDING,
+ ECORE_X_REGION_CLIP
+} Ecore_X_Region_Type;
+
+EAPI Ecore_X_Region ecore_x_region_new(Ecore_X_Rectangle *rects, int num);
+EAPI Ecore_X_Region ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap);
+EAPI Ecore_X_Region ecore_x_region_new_from_window(Ecore_X_Window win, Ecore_X_Region_Type type);
+EAPI Ecore_X_Region ecore_x_region_new_from_gc(Ecore_X_GC gc);
+EAPI Ecore_X_Region ecore_x_region_new_from_picture(Ecore_X_Picture picture);
+EAPI void ecore_x_region_free(Ecore_X_Region region);
+EAPI void ecore_x_region_set(Ecore_X_Region region, Ecore_X_Rectangle *rects, int num);
+EAPI void ecore_x_region_copy(Ecore_X_Region dest, Ecore_X_Region source);
+EAPI void ecore_x_region_combine(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2);
+EAPI void ecore_x_region_intersect(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2);
+EAPI void ecore_x_region_subtract(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2);
+EAPI void ecore_x_region_invert(Ecore_X_Region dest, Ecore_X_Rectangle *bounds, Ecore_X_Region source);
+EAPI void ecore_x_region_translate(Ecore_X_Region region, int dx, int dy);
+EAPI void ecore_x_region_extents(Ecore_X_Region dest, Ecore_X_Region source);
+EAPI Ecore_X_Rectangle *ecore_x_region_fetch(Ecore_X_Region region, int *num, Ecore_X_Rectangle *bounds);
+EAPI void ecore_x_region_expand(Ecore_X_Region dest, Ecore_X_Region source, unsigned int left, unsigned int right, unsigned int top, unsigned int bottom);
+EAPI void ecore_x_region_gc_clip_set(Ecore_X_Region region, Ecore_X_GC gc, int x_origin, int y_origin);
+EAPI void ecore_x_region_window_shape_set(Ecore_X_Region region, Ecore_X_Window win, Ecore_X_Shape_Type type, int x_offset, int y_offset);
+EAPI void ecore_x_region_picture_clip_set(Ecore_X_Region region, Ecore_X_Picture picture, int x_origin, int y_origin);
+
+/**
+ * xfixes selection notification request.
+ *
+ * This lets you choose which selections you want to get notifications for.
+ * @param selection The selection atom.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ * @since 1.1.0
+ */
+EAPI Eina_Bool ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection);
+
+/* XComposite Extension Support */
+EAPI Eina_Bool ecore_x_composite_query(void);
+EAPI void ecore_x_composite_redirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type);
+EAPI void ecore_x_composite_redirect_subwindows(Ecore_X_Window win, Ecore_X_Composite_Update_Type type);
+EAPI void ecore_x_composite_unredirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type);
+EAPI void ecore_x_composite_unredirect_subwindows(Ecore_X_Window win, Ecore_X_Composite_Update_Type type);
+EAPI Ecore_X_Pixmap ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win);
+EAPI void ecore_x_composite_window_events_disable(Ecore_X_Window win);
+EAPI void ecore_x_composite_window_events_enable(Ecore_X_Window win);
+EAPI Ecore_X_Window ecore_x_composite_render_window_enable(Ecore_X_Window root);
+EAPI void ecore_x_composite_render_window_disable(Ecore_X_Window root);
+
+/* XDamage Extension Support */
+typedef Ecore_X_ID Ecore_X_Damage;
+
+typedef enum _Ecore_X_Damage_Report_Level
+{
+ ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES,
+ ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES,
+ ECORE_X_DAMAGE_REPORT_BOUNDING_BOX,
+ ECORE_X_DAMAGE_REPORT_NON_EMPTY
+} Ecore_X_Damage_Report_Level;
+
+struct _Ecore_X_Event_Damage
+{
+ Ecore_X_Damage_Report_Level level;
+ Ecore_X_Drawable drawable;
+ Ecore_X_Damage damage;
+ int more;
+ Ecore_X_Time time;
+ Ecore_X_Rectangle area;
+ Ecore_X_Rectangle geometry;
+};
+
+typedef struct _Ecore_X_Event_Damage Ecore_X_Event_Damage;
+
+struct _Ecore_X_Event_Xkb
+{
+ int group;
+};
+typedef struct _Ecore_X_Event_Xkb Ecore_X_Event_Xkb; /** @since 1.7 */
+
+EAPI Eina_Bool ecore_x_damage_query(void);
+EAPI Ecore_X_Damage ecore_x_damage_new(Ecore_X_Drawable d, Ecore_X_Damage_Report_Level level);
+EAPI void ecore_x_damage_free(Ecore_X_Damage damage);
+EAPI void ecore_x_damage_subtract(Ecore_X_Damage damage, Ecore_X_Region repair, Ecore_X_Region parts);
+
+EAPI Eina_Bool ecore_x_screen_is_composited(int screen);
+EAPI void ecore_x_screen_is_composited_set(int screen, Ecore_X_Window win);
+
+EAPI Eina_Bool ecore_x_dpms_query(void);
+EAPI Eina_Bool ecore_x_dpms_capable_get(void);
+EAPI Eina_Bool ecore_x_dpms_enabled_get(void);
+EAPI void ecore_x_dpms_enabled_set(int enabled);
+EAPI void ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned int *off);
+EAPI Eina_Bool ecore_x_dpms_timeouts_set(unsigned int standby, unsigned int suspend, unsigned int off);
+EAPI unsigned int ecore_x_dpms_timeout_standby_get(void);
+EAPI unsigned int ecore_x_dpms_timeout_suspend_get(void);
+EAPI unsigned int ecore_x_dpms_timeout_off_get(void);
+EAPI void ecore_x_dpms_timeout_standby_set(unsigned int new_timeout);
+EAPI void ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout);
+EAPI void ecore_x_dpms_timeout_off_set(unsigned int new_timeout);
+
+EAPI Eina_Bool ecore_x_test_fake_key_down(const char *key);
+EAPI Eina_Bool ecore_x_test_fake_key_up(const char *key);
+EAPI Eina_Bool ecore_x_test_fake_key_press(const char *key);
+EAPI const char *ecore_x_keysym_string_get(int keysym);
+
+/**
+ * Given a keyname, return the keycode representing that key
+ * @param keyname The key from which to get the keycode.
+ * @return The keycode of the key.
+ *
+ * @since 1.2.0
+ */
+EAPI int ecore_x_keysym_keycode_get(const char *keyname);
+
+typedef struct _Ecore_X_Image Ecore_X_Image;
+
+EAPI Ecore_X_Image *ecore_x_image_new(int w, int h, Ecore_X_Visual vis, int depth);
+EAPI void ecore_x_image_free(Ecore_X_Image *im);
+EAPI Eina_Bool ecore_x_image_get(Ecore_X_Image *im, Ecore_X_Drawable draw, int x, int y, int sx, int sy, int w, int h);
+EAPI void ecore_x_image_put(Ecore_X_Image *im, Ecore_X_Drawable draw, Ecore_X_GC gc, int x, int y, int sx, int sy, int w, int h);
+EAPI void *ecore_x_image_data_get(Ecore_X_Image *im, int *bpl, int *rows, int *bpp);
+EAPI Eina_Bool ecore_x_image_is_argb32_get(Ecore_X_Image *im);
+
+EAPI Eina_Bool ecore_x_image_to_argb_convert(void *src, int sbpp, int sbpl, Ecore_X_Colormap c, Ecore_X_Visual v, int x, int y, int w, int h, unsigned int *dst, int dbpl, int dx, int dy);
+
+EAPI Eina_Bool ecore_x_input_multi_select(Ecore_X_Window win);
+EAPI Eina_Bool ecore_x_input_raw_select(Ecore_X_Window win); /**< @since 1.8 */
+
+EAPI Eina_Bool ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win);
+
+typedef enum _Ecore_X_Gesture_Event_Mask
+{
+ ECORE_X_GESTURE_EVENT_MASK_NONE = 0L,
+ ECORE_X_GESTURE_EVENT_MASK_FLICK = (1L << 0),
+ ECORE_X_GESTURE_EVENT_MASK_PAN = (1L << 1),
+ ECORE_X_GESTURE_EVENT_MASK_PINCHROTATION = (1L << 2),
+ ECORE_X_GESTURE_EVENT_MASK_TAP = (1L << 3),
+ ECORE_X_GESTURE_EVENT_MASK_TAPNHOLD = (1L << 4),
+ ECORE_X_GESTURE_EVENT_MASK_HOLD = (1L << 5),
+ ECORE_X_GESTURE_EVENT_MASK_GROUP = (1L << 6)
+} Ecore_X_Gesture_Event_Mask;
+
+typedef enum _Ecore_X_Gesture_Event_Type
+{
+ ECORE_X_GESTURE_EVENT_FLICK,
+ ECORE_X_GESTURE_EVENT_PAN,
+ ECORE_X_GESTURE_EVENT_PINCHROTATION,
+ ECORE_X_GESTURE_EVENT_TAP,
+ ECORE_X_GESTURE_EVENT_TAPNHOLD,
+ ECORE_X_GESTURE_EVENT_HOLD,
+ ECORE_X_GESTURE_EVENT_GROUP
+} Ecore_X_Gesture_Event_Type;
+
+typedef enum _Ecore_X_Gesture_Event_Subtype
+{
+ ECORE_X_GESTURE_END,
+ ECORE_X_GESTURE_BEGIN,
+ ECORE_X_GESTURE_UPDATE,
+ ECORE_X_GESTURE_DONE
+} Ecore_X_Gesture_Event_Subtype;
+
+typedef enum _Ecore_X_Gesture_Group_Subtype
+{
+ ECORE_X_GESTURE_GROUP_REMOVED,
+ ECORE_X_GESTURE_GROUP_ADDED,
+ ECORE_X_GESTURE_GROUP_CURRENT
+} Ecore_X_Gesture_Group_Subtype;
+
+typedef enum _Ecore_X_Gesture_Direction
+{
+ ECORE_X_GESTURE_NORTHWARD,
+ ECORE_X_GESTURE_NORTHEASTWARD,
+ ECORE_X_GESTURE_EASTWARD,
+ ECORE_X_GESTURE_SOUTHEASTWARD,
+ ECORE_X_GESTURE_SOUTHWARD,
+ ECORE_X_GESTURE_SOUTHWESTWARD,
+ ECORE_X_GESTURE_WESTWARD,
+ ECORE_X_GESTURE_NORTHWESTWARD
+} Ecore_X_Gesture_Direction;
+
+struct _Ecore_X_Event_Gesture_Notify_Flick
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int distance;
+ Ecore_X_Time duration;
+ Ecore_X_Gesture_Direction direction;
+ double angle;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_Pan
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int dx;
+ int dy;
+ int distance;
+ Ecore_X_Time duration;
+ Ecore_X_Gesture_Direction direction;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_PinchRotation
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int distance;
+ int cx;
+ int cy;
+ double zoom;
+ double angle;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_Tap
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int cx;
+ int cy;
+ int tap_repeat;
+ Ecore_X_Time interval;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_TapNHold
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int cx;
+ int cy;
+ Ecore_X_Time interval;
+ Ecore_X_Time hold_time;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_Hold
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Event_Subtype subtype;
+ int num_fingers;
+ int cx;
+ int cy;
+ Ecore_X_Time hold_time;
+};
+
+struct _Ecore_X_Event_Gesture_Notify_Group
+{
+ Ecore_X_Window win;
+ Ecore_X_Time time;
+ Ecore_X_Gesture_Group_Subtype subtype;
+ int num_groups;
+ int group_id;
+};
+
+EAPI Eina_Bool ecore_x_gesture_supported(void);
+
+EAPI Eina_Bool ecore_x_gesture_events_select(Ecore_X_Window win, Ecore_X_Gesture_Event_Mask mask);
+
+EAPI Ecore_X_Gesture_Event_Mask ecore_x_gesture_events_selected_get(Ecore_X_Window win);
+
+EAPI Eina_Bool ecore_x_gesture_event_grab(Ecore_X_Window win, Ecore_X_Gesture_Event_Type type, int num_fingers);
+
+EAPI Eina_Bool ecore_x_gesture_event_ungrab(Ecore_X_Window win, Ecore_X_Gesture_Event_Type type, int num_fingers);
+
+EAPI void ecore_x_e_illume_indicator_state_set(Ecore_X_Window win, Ecore_X_Illume_Indicator_State state);
+EAPI Ecore_X_Illume_Indicator_State ecore_x_e_illume_indicator_state_get(Ecore_X_Window win);
+EAPI void ecore_x_e_illume_indicator_state_send(Ecore_X_Window win, Ecore_X_Illume_Indicator_State state);
+
+EAPI void ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win, Ecore_X_Illume_Indicator_Opacity_Mode mode);
+
+EAPI Ecore_X_Illume_Indicator_Opacity_Mode ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win);
+
+EAPI void ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win, Ecore_X_Illume_Indicator_Opacity_Mode mode);
+
+EAPI void
+ecore_x_e_illume_window_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Window_State state);
+
+EAPI Ecore_X_Illume_Window_State ecore_x_e_illume_window_state_get(Ecore_X_Window win);
+EAPI void ecore_x_xkb_select_group(int group); /* @since 1.7 */
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#include <Ecore_X_Atoms.h>
+#include <Ecore_X_Cursor.h>
+
+#endif // ifndef _ECORE_X_H
diff --git a/src/lib/ecore_x/Ecore_X_Atoms.h b/src/lib/ecore_x/Ecore_X_Atoms.h
new file mode 100644
index 0000000000..ca6351d839
--- /dev/null
+++ b/src/lib/ecore_x/Ecore_X_Atoms.h
@@ -0,0 +1,292 @@
+#ifndef _ECORE_X_ATOMS_H
+#define _ECORE_X_ATOMS_H
+
+/**
+ * @file
+ * @brief Ecore X atoms
+ */
+
+/* generic atoms */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_ATOM;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_CARDINAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_COMPOUND_TEXT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_FILE_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_STRING;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_TEXT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_UTF8_STRING;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WINDOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_PIXMAP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_VISUALID;
+
+/* dnd atoms */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_XDND;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_XDND;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_AWARE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ENTER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_TYPE_LIST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_POSITION;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_COPY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_MOVE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_PRIVATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_ASK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LIST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LINK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_PROXY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_STATUS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_LEAVE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_DROP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_FINISHED;
+
+/* dnd atoms that need to be exposed to the application interface */
+EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_COPY;
+EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_MOVE;
+EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_LINK;
+EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_ASK;
+EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_PRIVATE;
+
+/* old E atom */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE;
+
+/* old Gnome atom */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WIN_LAYER;
+
+/* ICCCM: client properties */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_ICON_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_NORMAL_HINTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_SIZE_HINTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_HINTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLASS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_TRANSIENT_FOR;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_PROTOCOLS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_WINDOWS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COMMAND;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_MACHINE;
+
+/* ICCCM: window manager properties */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_ICON_SIZE;
+
+/* ICCCM: WM_STATEproperty */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CHANGE_STATE;
+
+/* ICCCM: WM_PROTOCOLS properties */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_TAKE_FOCUS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_SAVE_YOURSELF;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_DELETE_WINDOW;
+
+/* ICCCM: WM_COLORMAP properties */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_NOTIFY;
+
+/* ICCCM: session management properties */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SM_CLIENT_ID;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_LEADER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_WINDOW_ROLE;
+
+/* Motif WM atom */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_MOTIF_WM_HINTS;
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTED;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST_STACKING;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_VIEWPORT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CURRENT_DESKTOP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_NAMES;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_ACTIVE_WINDOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WORKAREA;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_VIRTUAL_ROOTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_LAYOUT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SHOWING_DESKTOP;
+
+/* pager */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLOSE_WINDOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_MOVERESIZE_WINDOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_MOVERESIZE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_RESTACK_WINDOW;
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_DESKTOP;
+
+/* window type */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND;
+
+/* state */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MODAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_STICKY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SHADED;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_HIDDEN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_ABOVE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_BELOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION;
+
+/* allowed actions */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MOVE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_RESIZE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_SHADE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_STICK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CLOSE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_ABOVE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_BELOW;
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT_PARTIAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_PID;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_HANDLED_ICONS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_USER_TIME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_ID;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_FRAME_EXTENTS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_PING;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_OPACITY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADOW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_TARGETS;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PRIMARY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_SECONDARY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_CLIPBOARD;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
+
+/* currently E specific virtual keyboard extension, aim to submit to netwm spec
+ * later */
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME;
+
+/* Illume specific atoms */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE_LIST;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CONFORMANT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_SINGLE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_BACK;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_HOME;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_NEW;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_DEL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLOSE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_START;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_END;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_ON;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN;
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_COUNTER;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_BEGIN;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_END;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_CANCEL;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_FLUSH;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_DUMP;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_PIXMAP;
+
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_PARENT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_POSITION;
+
+/* currently elementary and E specific extension */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_PROFILE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_PROFILE_LIST;
+
+/* for sliding window */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY;
+
+/* for SDB(Samsung Debug Bridge) */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_CONNECT;
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_DISCONNECT;
+#endif /* _ECORE_X_ATOMS_H */
diff --git a/src/lib/ecore_x/Ecore_X_Cursor.h b/src/lib/ecore_x/Ecore_X_Cursor.h
new file mode 100644
index 0000000000..807541e596
--- /dev/null
+++ b/src/lib/ecore_x/Ecore_X_Cursor.h
@@ -0,0 +1,87 @@
+#ifndef _ECORE_X_CURSOR_H
+#define _ECORE_X_CURSOR_H
+
+/**
+ * @file
+ * @brief Defines the various cursor types for the X Windows system.
+ */
+
+#define ECORE_X_CURSOR_X 0
+#define ECORE_X_CURSOR_ARROW 2
+#define ECORE_X_CURSOR_BASED_ARROW_DOWN 4
+#define ECORE_X_CURSOR_UP 6
+#define ECORE_X_CURSOR_BOAT 8
+#define ECORE_X_CURSOR_BOGOSITY 10
+#define ECORE_X_CURSOR_BOTTOM_LEFT_CORNER 12
+#define ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER 14
+#define ECORE_X_CURSOR_BOTTOM_SIDE 16
+#define ECORE_X_CURSOR_BOTTOM_TEE 18
+#define ECORE_X_CURSOR_BOX_SPIRAL 20
+#define ECORE_X_CURSOR_CENTER_PTR 22
+#define ECORE_X_CURSOR_CIRCLE 24
+#define ECORE_X_CURSOR_CLOCK 26
+#define ECORE_X_CURSOR_COFFEE_MUG 28
+#define ECORE_X_CURSOR_CROSS 30
+#define ECORE_X_CURSOR_CROSS_REVERSE 32
+#define ECORE_X_CURSOR_CROSSHAIR 34
+#define ECORE_X_CURSOR_DIAMOND_CROSS 36
+#define ECORE_X_CURSOR_DOT 38
+#define ECORE_X_CURSOR_DOT_BOX_MASK 40
+#define ECORE_X_CURSOR_DOUBLE_ARROW 42
+#define ECORE_X_CURSOR_DRAFT_LARGE 44
+#define ECORE_X_CURSOR_DRAFT_SMALL 46
+#define ECORE_X_CURSOR_DRAPED_BOX 48
+#define ECORE_X_CURSOR_EXCHANGE 50
+#define ECORE_X_CURSOR_FLEUR 52
+#define ECORE_X_CURSOR_GOBBLER 54
+#define ECORE_X_CURSOR_GUMBY 56
+#define ECORE_X_CURSOR_HAND1 58
+#define ECORE_X_CURSOR_HAND2 60
+#define ECORE_X_CURSOR_HEART 62
+#define ECORE_X_CURSOR_ICON 64
+#define ECORE_X_CURSOR_IRON_CROSS 66
+#define ECORE_X_CURSOR_LEFT_PTR 68
+#define ECORE_X_CURSOR_LEFT_SIDE 70
+#define ECORE_X_CURSOR_LEFT_TEE 72
+#define ECORE_X_CURSOR_LEFTBUTTON 74
+#define ECORE_X_CURSOR_LL_ANGLE 76
+#define ECORE_X_CURSOR_LR_ANGLE 78
+#define ECORE_X_CURSOR_MAN 80
+#define ECORE_X_CURSOR_MIDDLEBUTTON 82
+#define ECORE_X_CURSOR_MOUSE 84
+#define ECORE_X_CURSOR_PENCIL 86
+#define ECORE_X_CURSOR_PIRATE 88
+#define ECORE_X_CURSOR_PLUS 90
+#define ECORE_X_CURSOR_QUESTION_ARROW 92
+#define ECORE_X_CURSOR_RIGHT_PTR 94
+#define ECORE_X_CURSOR_RIGHT_SIDE 96
+#define ECORE_X_CURSOR_RIGHT_TEE 98
+#define ECORE_X_CURSOR_RIGHTBUTTON 100
+#define ECORE_X_CURSOR_RTL_LOGO 102
+#define ECORE_X_CURSOR_SAILBOAT 104
+#define ECORE_X_CURSOR_SB_DOWN_ARROW 106
+#define ECORE_X_CURSOR_SB_H_DOUBLE_ARROW 108
+#define ECORE_X_CURSOR_SB_LEFT_ARROW 110
+#define ECORE_X_CURSOR_SB_RIGHT_ARROW 112
+#define ECORE_X_CURSOR_SB_UP_ARROW 114
+#define ECORE_X_CURSOR_SB_V_DOUBLE_ARROW 116
+#define ECORE_X_CURSOR_SHUTTLE 118
+#define ECORE_X_CURSOR_SIZING 120
+#define ECORE_X_CURSOR_SPIDER 122
+#define ECORE_X_CURSOR_SPRAYCAN 124
+#define ECORE_X_CURSOR_STAR 126
+#define ECORE_X_CURSOR_TARGET 128
+#define ECORE_X_CURSOR_TCROSS 130
+#define ECORE_X_CURSOR_TOP_LEFT_ARROW 132
+#define ECORE_X_CURSOR_TOP_LEFT_CORNER 134
+#define ECORE_X_CURSOR_TOP_RIGHT_CORNER 136
+#define ECORE_X_CURSOR_TOP_SIDE 138
+#define ECORE_X_CURSOR_TOP_TEE 140
+#define ECORE_X_CURSOR_TREK 142
+#define ECORE_X_CURSOR_UL_ANGLE 144
+#define ECORE_X_CURSOR_UMBRELLA 146
+#define ECORE_X_CURSOR_UR_ANGLE 148
+#define ECORE_X_CURSOR_WATCH 150
+#define ECORE_X_CURSOR_XTERM 152
+
+#endif // ifndef _ECORE_X_CURSOR_H
diff --git a/src/lib/ecore_x/ecore_x_atoms_decl.h b/src/lib/ecore_x/ecore_x_atoms_decl.h
new file mode 100644
index 0000000000..155283efe6
--- /dev/null
+++ b/src/lib/ecore_x/ecore_x_atoms_decl.h
@@ -0,0 +1,602 @@
+/* generic atoms */
+EAPI Ecore_X_Atom ECORE_X_ATOM_ATOM = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_CARDINAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_COMPOUND_TEXT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_FILE_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_STRING = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_TEXT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_UTF8_STRING = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WINDOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_PIXMAP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_VISUALID = 0;
+
+/* dnd atoms */
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_XDND = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_XDND = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_AWARE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ENTER = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_TYPE_LIST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_POSITION = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_COPY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_MOVE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_PRIVATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_ASK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LIST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LINK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_DESCRIPTION = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_PROXY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_STATUS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_LEAVE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_DROP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_FINISHED = 0;
+
+/* dnd atoms that need to be exposed to the application interface */
+EAPI Ecore_X_Atom ECORE_X_DND_ACTION_COPY = 0;
+EAPI Ecore_X_Atom ECORE_X_DND_ACTION_MOVE = 0;
+EAPI Ecore_X_Atom ECORE_X_DND_ACTION_LINK = 0;
+EAPI Ecore_X_Atom ECORE_X_DND_ACTION_ASK = 0;
+EAPI Ecore_X_Atom ECORE_X_DND_ACTION_PRIVATE = 0;
+
+/* old E atom */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE = 0;
+
+/* old Gnome atom */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WIN_LAYER = 0;
+
+/* ICCCM atoms */
+
+/* ICCCM: client properties */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_ICON_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_NORMAL_HINTS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_SIZE_HINTS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_HINTS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLASS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_TRANSIENT_FOR = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_PROTOCOLS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_WINDOWS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COMMAND = 0; /* obsolete */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_MACHINE = 0; /* obsolete */
+
+/* ICCCM: window manager properties */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_ICON_SIZE = 0;
+
+/* ICCCM: WM_STATE property */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CHANGE_STATE = 0;
+
+/* ICCCM: WM_PROTOCOLS properties */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_TAKE_FOCUS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_SAVE_YOURSELF = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_DELETE_WINDOW = 0;
+
+/* ICCCM: WM_COLORMAP properties */
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_NOTIFY = 0;
+
+/* ICCCM: session management properties */
+EAPI Ecore_X_Atom ECORE_X_ATOM_SM_CLIENT_ID = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_LEADER = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_WM_WINDOW_ROLE = 0;
+
+/* Motif WM atom */
+EAPI Ecore_X_Atom ECORE_X_ATOM_MOTIF_WM_HINTS = 0;
+
+/* NetWM 1.3 atoms (http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html) */
+
+/*
+ * NetWM: Root Window Properties and related messages (complete)
+ */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTED = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST_STACKING = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_VIEWPORT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CURRENT_DESKTOP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_NAMES = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_ACTIVE_WINDOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WORKAREA = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_VIRTUAL_ROOTS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_LAYOUT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SHOWING_DESKTOP = 0;
+
+/*
+ * NetWM: Other Root Window Messages (complete)
+ */
+
+/* pager */
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLOSE_WINDOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_MOVERESIZE_WINDOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_MOVERESIZE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_RESTACK_WINDOW = 0;
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS = 0;
+
+/*
+ * NetWM: Application Window Properties (complete)
+ */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_DESKTOP = 0;
+
+/* window type */
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND = 0;
+
+/* state */
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MODAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_STICKY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SHADED = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_HIDDEN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_ABOVE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_BELOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION = 0;
+
+/* allowed actions */
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MOVE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_RESIZE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_SHADE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_STICK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CLOSE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_ABOVE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_BELOW = 0;
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT_PARTIAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_PID = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_HANDLED_ICONS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_USER_TIME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_ID = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_FRAME_EXTENTS = 0;
+
+/*
+ * NetWM: Window Manager Protocols (complete)
+ */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_PING = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER = 0;
+
+/*
+ * NetWM: Not in the spec
+ */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_OPACITY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADOW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADE = 0;
+
+/*
+ * Startup Notification (http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt)
+ */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO = 0;
+
+/* selection atoms */
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_TARGETS = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PRIMARY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_SECONDARY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_CLIPBOARD = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_PRIMARY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_SECONDARY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD = 0;
+
+/* currently E specific virtual keyboard extension, aim to submit to netwm spec
+ * later */
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME = 0;
+
+/* currently E specific illume extension */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE_LIST = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CONFORMANT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_SINGLE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_BACK = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_HOME = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLOSE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_NEW = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_DEL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_START = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_END = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_ON = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE= 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN = 0;
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_COUNTER = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_BEGIN = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_END = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_CANCEL = 0;
+
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_FLUSH = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_DUMP = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_PIXMAP = 0;
+
+/* currently Emotion and E17 specific extension */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_PARENT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_POSITION = 0;
+
+/* for sliding window */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY = 0;
+
+/* for SDB(Samsung Debug Bridge) */
+EAPI Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_CONNECT = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_DISCONNECT = 0;
+
+/* currently elementary and E specific extension */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_PROFILE = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_PROFILE_LIST = 0;
+
+typedef struct _Atom_Item Atom_Item;
+
+struct _Atom_Item
+{
+ const char *name;
+ Ecore_X_Atom *atom;
+};
+
+const Atom_Item atom_items[] =
+{
+ { "ATOM", &ECORE_X_ATOM_ATOM },
+ { "CARDINAL", &ECORE_X_ATOM_CARDINAL },
+ { "COMPOUND_TEXT", &ECORE_X_ATOM_COMPOUND_TEXT },
+ { "FILE_NAME", &ECORE_X_ATOM_FILE_NAME },
+ { "STRING", &ECORE_X_ATOM_STRING },
+ { "TEXT", &ECORE_X_ATOM_TEXT },
+ { "UTF8_STRING", &ECORE_X_ATOM_UTF8_STRING },
+ { "WINDOW", &ECORE_X_ATOM_WINDOW },
+ { "PIXMAP", &ECORE_X_ATOM_PIXMAP },
+ { "VISUALID", &ECORE_X_ATOM_VISUALID },
+
+ { "JXSelectionWindowProperty", &ECORE_X_ATOM_SELECTION_PROP_XDND },
+ { "XdndSelection", &ECORE_X_ATOM_SELECTION_XDND },
+ { "XdndAware", &ECORE_X_ATOM_XDND_AWARE },
+ { "XdndEnter", &ECORE_X_ATOM_XDND_ENTER },
+ { "XdndTypeList", &ECORE_X_ATOM_XDND_TYPE_LIST },
+ { "XdndPosition", &ECORE_X_ATOM_XDND_POSITION },
+ { "XdndActionCopy", &ECORE_X_ATOM_XDND_ACTION_COPY },
+ { "XdndActionMove", &ECORE_X_ATOM_XDND_ACTION_MOVE },
+ { "XdndActionPrivate", &ECORE_X_ATOM_XDND_ACTION_PRIVATE },
+ { "XdndActionAsk", &ECORE_X_ATOM_XDND_ACTION_ASK },
+ { "XdndActionList", &ECORE_X_ATOM_XDND_ACTION_LIST },
+ { "XdndActionLink", &ECORE_X_ATOM_XDND_ACTION_LINK },
+ { "XdndActionDescription", &ECORE_X_ATOM_XDND_ACTION_DESCRIPTION },
+ { "XdndProxy", &ECORE_X_ATOM_XDND_PROXY },
+ { "XdndStatus", &ECORE_X_ATOM_XDND_STATUS },
+ { "XdndLeave", &ECORE_X_ATOM_XDND_LEAVE },
+ { "XdndDrop", &ECORE_X_ATOM_XDND_DROP },
+ { "XdndFinished", &ECORE_X_ATOM_XDND_FINISHED },
+
+ { "XdndActionCopy", &ECORE_X_DND_ACTION_COPY },
+ { "XdndActionMove", &ECORE_X_DND_ACTION_MOVE },
+ { "XdndActionLink", &ECORE_X_DND_ACTION_LINK },
+ { "XdndActionAsk", &ECORE_X_DND_ACTION_ASK },
+ { "XdndActionPrivate", &ECORE_X_DND_ACTION_PRIVATE },
+
+ { "_E_FRAME_SIZE", &ECORE_X_ATOM_E_FRAME_SIZE },
+
+ { "_WIN_LAYER", &ECORE_X_ATOM_WIN_LAYER },
+
+ { "WM_NAME", &ECORE_X_ATOM_WM_NAME },
+ { "WM_ICON_NAME", &ECORE_X_ATOM_WM_ICON_NAME },
+ { "WM_NORMAL_HINTS", &ECORE_X_ATOM_WM_NORMAL_HINTS },
+ { "WM_SIZE_HINTS", &ECORE_X_ATOM_WM_SIZE_HINTS },
+ { "WM_HINTS", &ECORE_X_ATOM_WM_HINTS },
+ { "WM_CLASS", &ECORE_X_ATOM_WM_CLASS },
+ { "WM_TRANSIENT_FOR", &ECORE_X_ATOM_WM_TRANSIENT_FOR },
+ { "WM_PROTOCOLS", &ECORE_X_ATOM_WM_PROTOCOLS },
+ { "WM_COLORMAP_WINDOWS", &ECORE_X_ATOM_WM_COLORMAP_WINDOWS },
+ { "WM_COMMAND", &ECORE_X_ATOM_WM_COMMAND },
+ { "WM_CLIENT_MACHINE", &ECORE_X_ATOM_WM_CLIENT_MACHINE },
+
+ { "WM_STATE", &ECORE_X_ATOM_WM_STATE },
+ { "WM_ICON_SIZE", &ECORE_X_ATOM_WM_ICON_SIZE },
+
+ { "WM_CHANGE_STATE", &ECORE_X_ATOM_WM_CHANGE_STATE },
+
+ { "WM_TAKE_FOCUS", &ECORE_X_ATOM_WM_TAKE_FOCUS },
+ { "WM_SAVE_YOURSELF", &ECORE_X_ATOM_WM_SAVE_YOURSELF },
+ { "WM_DELETE_WINDOW", &ECORE_X_ATOM_WM_DELETE_WINDOW },
+
+ { "WM_COLORMAP_NOTIFY", &ECORE_X_ATOM_WM_COLORMAP_NOTIFY },
+
+ { "SM_CLIENT_ID", &ECORE_X_ATOM_SM_CLIENT_ID },
+ { "WM_CLIENT_LEADER", &ECORE_X_ATOM_WM_CLIENT_LEADER },
+ { "WM_WINDOW_ROLE", &ECORE_X_ATOM_WM_WINDOW_ROLE },
+
+ { "_MOTIF_WM_HINTS", &ECORE_X_ATOM_MOTIF_WM_HINTS },
+
+ { "_NET_SUPPORTED", &ECORE_X_ATOM_NET_SUPPORTED },
+ { "_NET_CLIENT_LIST", &ECORE_X_ATOM_NET_CLIENT_LIST },
+ { "_NET_CLIENT_LIST_STACKING", &ECORE_X_ATOM_NET_CLIENT_LIST_STACKING },
+ { "_NET_NUMBER_OF_DESKTOPS", &ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS },
+ { "_NET_DESKTOP_GEOMETRY", &ECORE_X_ATOM_NET_DESKTOP_GEOMETRY },
+ { "_NET_DESKTOP_VIEWPORT", &ECORE_X_ATOM_NET_DESKTOP_VIEWPORT },
+ { "_NET_CURRENT_DESKTOP", &ECORE_X_ATOM_NET_CURRENT_DESKTOP },
+ { "_NET_DESKTOP_NAMES", &ECORE_X_ATOM_NET_DESKTOP_NAMES },
+ { "_NET_ACTIVE_WINDOW", &ECORE_X_ATOM_NET_ACTIVE_WINDOW },
+ { "_NET_WORKAREA", &ECORE_X_ATOM_NET_WORKAREA },
+ { "_NET_SUPPORTING_WM_CHECK", &ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK },
+ { "_NET_VIRTUAL_ROOTS", &ECORE_X_ATOM_NET_VIRTUAL_ROOTS },
+ { "_NET_DESKTOP_LAYOUT", &ECORE_X_ATOM_NET_DESKTOP_LAYOUT },
+ { "_NET_SHOWING_DESKTOP", &ECORE_X_ATOM_NET_SHOWING_DESKTOP },
+
+ { "_NET_CLOSE_WINDOW", &ECORE_X_ATOM_NET_CLOSE_WINDOW },
+ { "_NET_MOVERESIZE_WINDOW", &ECORE_X_ATOM_NET_MOVERESIZE_WINDOW },
+ { "_NET_WM_MOVERESIZE", &ECORE_X_ATOM_NET_WM_MOVERESIZE },
+ { "_NET_RESTACK_WINDOW", &ECORE_X_ATOM_NET_RESTACK_WINDOW },
+
+ { "_NET_REQUEST_FRAME_EXTENTS", &ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS },
+
+ { "_NET_WM_NAME", &ECORE_X_ATOM_NET_WM_NAME },
+ { "_NET_WM_VISIBLE_NAME", &ECORE_X_ATOM_NET_WM_VISIBLE_NAME },
+ { "_NET_WM_ICON_NAME", &ECORE_X_ATOM_NET_WM_ICON_NAME },
+ { "_NET_WM_VISIBLE_ICON_NAME", &ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME },
+ { "_NET_WM_DESKTOP", &ECORE_X_ATOM_NET_WM_DESKTOP },
+
+ { "_NET_WM_WINDOW_TYPE", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE },
+ { "_NET_WM_WINDOW_TYPE_DESKTOP", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP },
+ { "_NET_WM_WINDOW_TYPE_DOCK", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK },
+ { "_NET_WM_WINDOW_TYPE_TOOLBAR", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR },
+ { "_NET_WM_WINDOW_TYPE_MENU", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU },
+ { "_NET_WM_WINDOW_TYPE_UTILITY", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY },
+ { "_NET_WM_WINDOW_TYPE_SPLASH", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH },
+ { "_NET_WM_WINDOW_TYPE_DIALOG", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG },
+ { "_NET_WM_WINDOW_TYPE_NORMAL", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL },
+ { "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
+ &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU },
+ { "_NET_WM_WINDOW_TYPE_POPUP_MENU",
+ &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU },
+ { "_NET_WM_WINDOW_TYPE_TOOLTIP", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP },
+ { "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+ &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION },
+ { "_NET_WM_WINDOW_TYPE_COMBO", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO },
+ { "_NET_WM_WINDOW_TYPE_DND", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND },
+
+ { "_NET_WM_STATE", &ECORE_X_ATOM_NET_WM_STATE },
+ { "_NET_WM_STATE_MODAL", &ECORE_X_ATOM_NET_WM_STATE_MODAL },
+ { "_NET_WM_STATE_STICKY", &ECORE_X_ATOM_NET_WM_STATE_STICKY },
+ { "_NET_WM_STATE_MAXIMIZED_VERT",
+ &ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT },
+ { "_NET_WM_STATE_MAXIMIZED_HORZ",
+ &ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ },
+ { "_NET_WM_STATE_SHADED", &ECORE_X_ATOM_NET_WM_STATE_SHADED },
+ { "_NET_WM_STATE_SKIP_TASKBAR", &ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR },
+ { "_NET_WM_STATE_SKIP_PAGER", &ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER },
+ { "_NET_WM_STATE_HIDDEN", &ECORE_X_ATOM_NET_WM_STATE_HIDDEN },
+ { "_NET_WM_STATE_FULLSCREEN", &ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN },
+ { "_NET_WM_STATE_ABOVE", &ECORE_X_ATOM_NET_WM_STATE_ABOVE },
+ { "_NET_WM_STATE_BELOW", &ECORE_X_ATOM_NET_WM_STATE_BELOW },
+ { "_NET_WM_STATE_DEMANDS_ATTENTION",
+ &ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION },
+
+ { "_NET_WM_ALLOWED_ACTIONS", &ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS },
+ { "_NET_WM_ACTION_MOVE", &ECORE_X_ATOM_NET_WM_ACTION_MOVE },
+ { "_NET_WM_ACTION_RESIZE", &ECORE_X_ATOM_NET_WM_ACTION_RESIZE },
+ { "_NET_WM_ACTION_MINIMIZE", &ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE },
+ { "_NET_WM_ACTION_SHADE", &ECORE_X_ATOM_NET_WM_ACTION_SHADE },
+ { "_NET_WM_ACTION_STICK", &ECORE_X_ATOM_NET_WM_ACTION_STICK },
+ { "_NET_WM_ACTION_MAXIMIZE_HORZ",
+ &ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ },
+ { "_NET_WM_ACTION_MAXIMIZE_VERT",
+ &ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT },
+ { "_NET_WM_ACTION_FULLSCREEN", &ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN },
+ { "_NET_WM_ACTION_CHANGE_DESKTOP",
+ &ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP },
+ { "_NET_WM_ACTION_CLOSE", &ECORE_X_ATOM_NET_WM_ACTION_CLOSE },
+ { "_NET_WM_ACTION_ABOVE", &ECORE_X_ATOM_NET_WM_ACTION_ABOVE },
+ { "_NET_WM_ACTION_BELOW", &ECORE_X_ATOM_NET_WM_ACTION_BELOW },
+
+ { "_NET_WM_STRUT", &ECORE_X_ATOM_NET_WM_STRUT },
+ { "_NET_WM_STRUT_PARTIAL", &ECORE_X_ATOM_NET_WM_STRUT_PARTIAL },
+ { "_NET_WM_ICON_GEOMETRY", &ECORE_X_ATOM_NET_WM_ICON_GEOMETRY },
+ { "_NET_WM_ICON", &ECORE_X_ATOM_NET_WM_ICON },
+ { "_NET_WM_PID", &ECORE_X_ATOM_NET_WM_PID },
+ { "_NET_WM_HANDLED_ICONS", &ECORE_X_ATOM_NET_WM_HANDLED_ICONS },
+ { "_NET_WM_USER_TIME", &ECORE_X_ATOM_NET_WM_USER_TIME },
+ { "_NET_STARTUP_ID", &ECORE_X_ATOM_NET_STARTUP_ID },
+ { "_NET_FRAME_EXTENTS", &ECORE_X_ATOM_NET_FRAME_EXTENTS },
+
+ { "_NET_WM_PING", &ECORE_X_ATOM_NET_WM_PING },
+ { "_NET_WM_SYNC_REQUEST", &ECORE_X_ATOM_NET_WM_SYNC_REQUEST },
+ { "_NET_WM_SYNC_REQUEST_COUNTER",
+ &ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER },
+
+ { "_NET_WM_WINDOW_OPACITY", &ECORE_X_ATOM_NET_WM_WINDOW_OPACITY },
+ { "_NET_WM_WINDOW_SHADOW", &ECORE_X_ATOM_NET_WM_WINDOW_SHADOW },
+ { "_NET_WM_WINDOW_SHADE", &ECORE_X_ATOM_NET_WM_WINDOW_SHADE },
+
+ { "TARGETS", &ECORE_X_ATOM_SELECTION_TARGETS },
+ { "CLIPBOARD", &ECORE_X_ATOM_SELECTION_CLIPBOARD },
+ { "PRIMARY", &ECORE_X_ATOM_SELECTION_PRIMARY },
+ { "SECONDARY", &ECORE_X_ATOM_SELECTION_SECONDARY },
+ { "_ECORE_SELECTION_PRIMARY", &ECORE_X_ATOM_SELECTION_PROP_PRIMARY },
+ { "_ECORE_SELECTION_SECONDARY", &ECORE_X_ATOM_SELECTION_PROP_SECONDARY },
+ { "_ECORE_SELECTION_CLIPBOARD", &ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD },
+
+ { "_E_VIRTUAL_KEYBOARD", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD },
+ { "_E_VIRTUAL_KEYBOARD_STATE", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE },
+ { "_E_VIRTUAL_KEYBOARD_ON", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON },
+ { "_E_VIRTUAL_KEYBOARD_OFF", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF },
+ { "_E_VIRTUAL_KEYBOARD_ALPHA", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA },
+ { "_E_VIRTUAL_KEYBOARD_NUMERIC", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC },
+ { "_E_VIRTUAL_KEYBOARD_PIN", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN },
+ { "_E_VIRTUAL_KEYBOARD_PHONE_NUMBER",
+ &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER },
+ { "_E_VIRTUAL_KEYBOARD_HEX", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX },
+ { "_E_VIRTUAL_KEYBOARD_TERMINAL",
+ &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL },
+ { "_E_VIRTUAL_KEYBOARD_PASSWORD",
+ &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD },
+ { "_E_VIRTUAL_KEYBOARD_IP", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP },
+ { "_E_VIRTUAL_KEYBOARD_HOST", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST },
+ { "_E_VIRTUAL_KEYBOARD_FILE", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE },
+ { "_E_VIRTUAL_KEYBOARD_URL", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL },
+ { "_E_VIRTUAL_KEYBOARD_KEYPAD", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD },
+ { "_E_VIRTUAL_KEYBOARD_J2ME", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME },
+
+ { "_E_ILLUME_ZONE", &ECORE_X_ATOM_E_ILLUME_ZONE },
+ { "_E_ILLUME_ZONE_LIST", &ECORE_X_ATOM_E_ILLUME_ZONE_LIST },
+ { "_E_ILLUME_CONFORMANT", &ECORE_X_ATOM_E_ILLUME_CONFORMANT },
+ { "_E_ILLUME_MODE", &ECORE_X_ATOM_E_ILLUME_MODE },
+ { "_E_ILLUME_MODE_SINGLE", &ECORE_X_ATOM_E_ILLUME_MODE_SINGLE },
+ { "_E_ILLUME_MODE_DUAL_TOP", &ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP },
+ { "_E_ILLUME_MODE_DUAL_LEFT", &ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT },
+ { "_E_ILLUME_FOCUS_BACK", &ECORE_X_ATOM_E_ILLUME_FOCUS_BACK },
+ { "_E_ILLUME_FOCUS_FORWARD", &ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD },
+ { "_E_ILLUME_FOCUS_HOME", &ECORE_X_ATOM_E_ILLUME_FOCUS_HOME },
+ { "_E_ILLUME_CLOSE", &ECORE_X_ATOM_E_ILLUME_CLOSE },
+ { "_E_ILLUME_HOME_NEW", &ECORE_X_ATOM_E_ILLUME_HOME_NEW },
+ { "_E_ILLUME_HOME_DEL", &ECORE_X_ATOM_E_ILLUME_HOME_DEL },
+ { "_E_ILLUME_DRAG", &ECORE_X_ATOM_E_ILLUME_DRAG },
+ { "_E_ILLUME_DRAG_LOCKED", &ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED },
+ { "_E_ILLUME_DRAG_START", &ECORE_X_ATOM_E_ILLUME_DRAG_START },
+ { "_E_ILLUME_DRAG_END", &ECORE_X_ATOM_E_ILLUME_DRAG_END },
+ { "_E_ILLUME_INDICATOR_GEOMETRY",
+ &ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY },
+ { "_E_ILLUME_SOFTKEY_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY },
+ { "_E_ILLUME_KEYBOARD_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY },
+ { "_E_ILLUME_QUICKPANEL", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL },
+ { "_E_ILLUME_QUICKPANEL_STATE", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE },
+ { "_E_ILLUME_QUICKPANEL_STATE_TOGGLE",
+ &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE },
+ { "_E_ILLUME_QUICKPANEL_ON", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON },
+ { "_E_ILLUME_QUICKPANEL_OFF", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF },
+ { "_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR",
+ &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR },
+ { "_E_ILLUME_QUICKPANEL_PRIORITY_MINOR",
+ &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR },
+ { "_E_ILLUME_QUICKPANEL_ZONE", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE },
+ { "_E_ILLUME_QUICKPANEL_POSITION_UPDATE",
+ &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE },
+ { "_E_ILLUME_INDICATOR_STATE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE },
+ { "_E_ILLUME_INDICATOR_ON", &ECORE_X_ATOM_E_ILLUME_INDICATOR_ON },
+ { "_E_ILLUME_INDICATOR_OFF", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF },
+ { "_E_ILLUME_INDICATOR_OPACITY_MODE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE },
+ { "_E_ILLUME_INDICATOR_OPAQUE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE },
+ { "_E_ILLUME_INDICATOR_TRANSLUCENT", &ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT },
+ { "_E_ILLUME_INDICATOR_TRANSPARENT", &ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT },
+ { "_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLES", &ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE },
+ { "_E_ILLUME_ROTATE_WINDOW_ANGLE", &ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE },
+ { "_E_ILLUME_ROTATE_ROOT_ANGLE", &ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE },
+ { "_E_ILLUME_CLIPBOARD_STATE", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE },
+ { "_E_ILLUME_CLIPBOARD_ON", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON },
+ { "_E_ILLUME_CLIPBOARD_OFF", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF },
+ { "_E_ILLUME_CLIPBOARD_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY },
+ { "_E_ILLUME_WINDOW_STATE", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE },
+ { "_E_ILLUME_WINDOW_STATE_NORMAL", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL },
+ { "_E_ILLUME_WINDOW_STATE_FLOATING", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING },
+ { "_E_ILLUME_ACCESS_CONTROL", &ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL },
+ { "_E_ILLUME_ACCESS_ACTION_NEXT", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT },
+ { "_E_ILLUME_ACCESS_ACTION_PREV", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV },
+ { "_E_ILLUME_ACCESS_ACTION_ACTIVATE", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE },
+ { "_E_ILLUME_ACCESS_ACTION_READ", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ },
+ { "_E_ILLUME_ACCESS_ACTION_READ_NEXT", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT },
+ { "_E_ILLUME_ACCESS_ACTION_READ_PREV", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV },
+ { "_E_ILLUME_ACCESS_ACTION_UP", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP },
+ { "_E_ILLUME_ACCESS_ACTION_DOWN", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN },
+ { "_E_COMP_SYNC_COUNTER", &ECORE_X_ATOM_E_COMP_SYNC_COUNTER },
+ { "_E_COMP_SYNC_DRAW_DONE", &ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE },
+ { "_E_COMP_SYNC_SUPPORTED", &ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED },
+ { "_E_COMP_SYNC_BEGIN", &ECORE_X_ATOM_E_COMP_SYNC_BEGIN },
+ { "_E_COMP_SYNC_END", &ECORE_X_ATOM_E_COMP_SYNC_END },
+ { "_E_COMP_SYNC_CANCEL", &ECORE_X_ATOM_E_COMP_SYNC_CANCEL },
+
+ { "_E_COMP_FLUSH", &ECORE_X_ATOM_E_COMP_FLUSH },
+ { "_E_COMP_DUMP", &ECORE_X_ATOM_E_COMP_DUMP },
+ { "_E_COMP_PIXMAP", &ECORE_X_ATOM_E_COMP_PIXMAP },
+ { "_E_VIDEO_PARENT", &ECORE_X_ATOM_E_VIDEO_PARENT },
+ { "_E_VIDEO_POSITION", &ECORE_X_ATOM_E_VIDEO_POSITION }
+};
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb.c b/src/lib/ecore_x/xcb/ecore_xcb.c
new file mode 100644
index 0000000000..2f1e1a2601
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb.c
@@ -0,0 +1,1583 @@
+#include "ecore_xcb_private.h"
+#include <X11/Xlib-xcb.h>
+#include <dlfcn.h>
+
+/* local function prototypes */
+static int _ecore_xcb_shutdown(Eina_Bool close_display);
+static Eina_Bool _ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED);
+static Eina_Bool _ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED);
+static Eina_Bool _ecore_xcb_idle_enter(void *data EINA_UNUSED);
+
+/* local variables */
+static int _ecore_xcb_init_count = 0;
+static int _ecore_xcb_grab_count = 0;
+static Ecore_Fd_Handler *_ecore_xcb_fd_handler = NULL;
+static xcb_generic_event_t *_ecore_xcb_event_buffered = NULL;
+static Ecore_Idle_Enterer *_ecore_xcb_idle_enterer = NULL;
+
+/* external variables */
+int _ecore_xcb_log_dom = -1;
+Ecore_X_Display *_ecore_xcb_display = NULL;
+Ecore_X_Connection *_ecore_xcb_conn = NULL;
+Ecore_X_Screen *_ecore_xcb_screen = NULL;
+Ecore_X_Atom _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_NUM];
+double _ecore_xcb_double_click_time = 0.25;
+
+/**
+ * @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions
+ *
+ * Functions that start and shut down the Ecore X Library.
+ */
+
+/**
+ * Initialize the X display connection to the given display.
+ *
+ * @param name Display target name. If @c NULL, the default display is
+ * assumed.
+ * @return The number of times the library has been initialized without
+ * being shut down. 0 is returned if an error occurs.
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_init(const char *name)
+{
+ char *gl = NULL;
+ uint32_t mask, list[1];
+
+ /* check if we have initialized already */
+ if (++_ecore_xcb_init_count != 1)
+ return _ecore_xcb_init_count;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ /* try to initialize eina */
+ if (!eina_init()) return --_ecore_xcb_init_count;
+
+ /* setup ecore_xcb log domain */
+ _ecore_xcb_log_dom =
+ eina_log_domain_register("ecore_x", ECORE_XCB_DEFAULT_LOG_COLOR);
+ if (_ecore_xcb_log_dom < 0)
+ {
+ EINA_LOG_ERR("Cannot create Ecore Xcb log domain");
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ /* try to initialize ecore */
+ if (!ecore_init())
+ {
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ /* try to initialize ecore_event */
+ if (!ecore_event_init())
+ {
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ /* NB: XLib has XInitThreads */
+
+ /* check for env var which says we are not going to use GL @ all
+ *
+ * NB: This is done because if someone wants a 'pure' xcb implementation
+ * of ecore_x, all they need do is export this variable in the environment
+ * and ecore_x will not use xlib stuff at all.
+ *
+ * The upside is you can get pure xcb-based ecore_x (w/ all the speed), but
+ * there is a down-side here in that you cannot get OpenGL without XLib :(
+ */
+ if ((gl = getenv("ECORE_X_NO_XLIB")))
+ {
+ /* we found the env var that says 'Yes, we are not ever gonna try
+ * OpenGL so it is safe to not use XLib at all' */
+
+ /* try to connect to the display server */
+ _ecore_xcb_conn = xcb_connect(name, NULL);
+ }
+ else
+ {
+ /* env var was not specified, so we will assume that the user
+ * may want opengl @ some point. connect this way for opengl to work */
+ void *libxcb, *libxlib;
+ Display *(*_real_display)(const char *display);
+ xcb_connection_t *(*_real_connection)(Display * dpy);
+ void (*_real_queue)(Display *dpy, enum XEventQueueOwner owner);
+ int (*_real_close)(Display *dpy);
+#ifdef EVAS_FRAME_QUEUING
+ Status (*_real_threads)(void);
+#endif
+
+ /* want to dlopen here to avoid actual library linkage */
+ libxlib = dlopen("libX11.so", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxlib)
+ libxlib = dlopen("libX11.so.6", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxlib)
+ libxlib = dlopen("libX11.so.6.3.0", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxlib)
+ {
+ ERR("Could not dlsym to libX11");
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ libxcb = dlopen("libX11-xcb.so", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxcb)
+ libxcb = dlopen("libX11-xcb.so.1", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxcb)
+ libxcb = dlopen("libX11-xcb.so.1.0.0", (RTLD_LAZY | RTLD_GLOBAL));
+ if (!libxcb)
+ {
+ ERR("Could not dlsym to libX11-xcb");
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ _real_display = dlsym(libxlib, "XOpenDisplay");
+ _real_close = dlsym(libxlib, "XCloseDisplay");
+ _real_connection = dlsym(libxcb, "XGetXCBConnection");
+ _real_queue = dlsym(libxcb, "XSetEventQueueOwner");
+#ifdef EVAS_FRAME_QUEUING
+ _real_threads = dlsym(libxlib, "XInitThreads");
+#endif
+
+ if (_real_display)
+ {
+#ifdef EVAS_FRAME_QUEUING
+ if (_real_threads) _real_threads();
+#endif
+ _ecore_xcb_display = _real_display(name);
+ if (!_ecore_xcb_display)
+ {
+ ERR("Could not open Display via XLib");
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+ if (_real_connection)
+ _ecore_xcb_conn = _real_connection(_ecore_xcb_display);
+ if (!_ecore_xcb_conn)
+ {
+ ERR("Could not get XCB Connection from XLib");
+
+ if (_real_close) _real_close(_ecore_xcb_display);
+
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+ if (_real_queue)
+ _real_queue(_ecore_xcb_display, XCBOwnsEventQueue);
+ }
+ }
+
+ if (xcb_connection_has_error(_ecore_xcb_conn))
+ {
+ CRIT("XCB Connection has error");
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+ ecore_event_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+ return --_ecore_xcb_init_count;
+ }
+
+ /* grab the default screen */
+ _ecore_xcb_screen =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
+
+ /* NB: This method of init/finalize extensions first, then atoms
+ * Does end up being 2 round trips to X, BUT if we do extensions init then
+ * atoms init first, and call the 'finalize' functions later, we end up
+ * being slower, so it's a trade-off. This current method clocks in
+ * around 0.003 for fetching atoms VS 0.010 for init both then finalize */
+
+ /* prefetch extension data */
+ _ecore_xcb_extensions_init();
+
+ /* finalize extensions */
+ _ecore_xcb_extensions_finalize();
+
+ /* set keyboard autorepeat */
+ mask = XCB_KB_AUTO_REPEAT_MODE;
+ list[0] = XCB_AUTO_REPEAT_MODE_ON;
+ xcb_change_keyboard_control(_ecore_xcb_conn, mask, list);
+
+ /* setup xcb events */
+ _ecore_xcb_events_init();
+
+ /* setup xcb keymasks */
+ _ecore_xcb_keymap_init();
+
+ /* finalize xcb keymasks */
+ _ecore_xcb_keymap_finalize();
+
+ /* setup ecore fd handler */
+ _ecore_xcb_fd_handler =
+ ecore_main_fd_handler_add(xcb_get_file_descriptor(_ecore_xcb_conn),
+ ECORE_FD_READ, _ecore_xcb_fd_handle,
+ _ecore_xcb_conn, _ecore_xcb_fd_handle_buff,
+ _ecore_xcb_conn);
+
+ if (!_ecore_xcb_fd_handler)
+ return _ecore_xcb_shutdown(EINA_TRUE);
+
+ /* prefetch atoms */
+ _ecore_xcb_atoms_init();
+
+ /* finalize atoms */
+ _ecore_xcb_atoms_finalize();
+
+ /* icccm_init: dummy function */
+ ecore_x_icccm_init();
+
+ /* setup netwm */
+ ecore_x_netwm_init();
+
+ /* old e hints init: dummy function */
+ ecore_x_e_init();
+
+ _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] =
+ ECORE_X_ATOM_WM_DELETE_WINDOW;
+ _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] =
+ ECORE_X_ATOM_WM_TAKE_FOCUS;
+ _ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_PING] =
+ ECORE_X_ATOM_NET_WM_PING;
+ _ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] =
+ ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+
+ /* setup selection */
+ _ecore_xcb_selection_init();
+
+ /* setup dnd */
+ _ecore_xcb_dnd_init();
+
+ _ecore_xcb_idle_enterer =
+ ecore_idle_enterer_add(_ecore_xcb_idle_enter, NULL);
+
+ return _ecore_xcb_init_count;
+}
+
+/**
+ * Shuts down the Ecore X library.
+ *
+ * In shutting down the library, the X display connection is terminated
+ * and any event handlers for it are removed.
+ *
+ * @return The number of times the library has been initialized without
+ * being shut down.
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_shutdown(void)
+{
+ return _ecore_xcb_shutdown(EINA_TRUE);
+}
+
+/**
+ * Shuts down the Ecore X library.
+ *
+ * As ecore_x_shutdown, except do not close Display, only connection.
+ *
+ * @return The number of times the library has been initialized without
+ * being shut down. 0 is returned if an error occurs.
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_disconnect(void)
+{
+ return _ecore_xcb_shutdown(EINA_FALSE);
+}
+
+/**
+ * @defgroup Ecore_X_Flush_Group X Synchronization Functions
+ *
+ * Functions that ensure that all commands that have been issued by the
+ * Ecore X library have been sent to the server.
+ */
+
+/**
+ * Sends all X commands in the X Display buffer.
+ * @ingroup Ecore_X_Flush_Group
+ */
+EAPI void
+ecore_x_flush(void)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ CHECK_XCB_CONN;
+ xcb_flush(_ecore_xcb_conn);
+}
+
+/**
+ * Retrieves the Ecore_X_Screen handle used for the current X connection.
+ * @return The current default screen.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI Ecore_X_Screen *
+ecore_x_default_screen_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return (Ecore_X_Screen *)_ecore_xcb_screen;
+}
+
+EAPI Ecore_X_Connection *
+ecore_x_connection_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ CHECK_XCB_CONN;
+ return (Ecore_X_Connection *)_ecore_xcb_conn;
+}
+
+/**
+ * Return the last event time
+ */
+EAPI Ecore_X_Time
+ecore_x_current_time_get(void)
+{
+ return _ecore_xcb_events_last_time_get();
+}
+
+/**
+ * Flushes the command buffer and waits until all requests have been
+ * processed by the server.
+ * @ingroup Ecore_X_Flush_Group
+ */
+EAPI void
+ecore_x_sync(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ CHECK_XCB_CONN;
+ free(xcb_get_input_focus_reply(_ecore_xcb_conn,
+ xcb_get_input_focus_unchecked(_ecore_xcb_conn),
+ NULL));
+}
+
+EAPI void
+ecore_x_grab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ CHECK_XCB_CONN;
+ _ecore_xcb_grab_count++;
+ if (_ecore_xcb_grab_count == 1)
+ xcb_grab_server(_ecore_xcb_conn);
+}
+
+EAPI void
+ecore_x_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ CHECK_XCB_CONN;
+ _ecore_xcb_grab_count--;
+ if (_ecore_xcb_grab_count < 0) _ecore_xcb_grab_count = 0;
+ if (_ecore_xcb_grab_count == 0)
+ xcb_ungrab_server(_ecore_xcb_conn);
+}
+
+/**
+ * Send client message with given type and format 32.
+ *
+ * @param win The window the message is sent to.
+ * @param type The client message type.
+ * @param mask The mask of the message to be sent.
+ * @param d0 The client message data item 1
+ * @param d1 The client message data item 2
+ * @param d2 The client message data item 3
+ * @param d3 The client message data item 4
+ * @param d4 The client message data item 5
+ *
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type,
+ Ecore_X_Event_Mask mask,
+ long d0, long d1, long d2, long d3, long d4)
+{
+ xcb_client_message_event_t ev;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = type;
+ ev.data.data32[0] = (uint32_t)d0;
+ ev.data.data32[1] = (uint32_t)d1;
+ ev.data.data32[2] = (uint32_t)d2;
+ ev.data.data32[3] = (uint32_t)d3;
+ ev.data.data32[4] = (uint32_t)d4;
+
+ cookie = xcb_send_event(_ecore_xcb_conn, 0, win, mask, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ DBG("Problem Sending Event");
+ DBG("\tType: %d", type);
+ DBG("\tWin: %d", win);
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+/**
+ * Send client message with given type and format 8.
+ *
+ * @param win The window the message is sent to.
+ * @param type The client message type.
+ * @param data Data to be sent.
+ * @param len Number of data bytes, max @c 20.
+ *
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type,
+ const void *data, int len)
+{
+ xcb_client_message_event_t ev;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 8;
+ ev.window = win;
+ ev.type = type;
+ if (len > 20) len = 20;
+ memcpy(ev.data.data8, data, len);
+ memset(ev.data.data8 + len, 0, 20 - len);
+
+ cookie = xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ DBG("Problem Sending Event");
+ DBG("\tType: %d", type);
+ DBG("\tWin: %d", win);
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b)
+{
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *reply;
+ xcb_button_press_event_t ev;
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+ Ecore_X_Window root = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ecore_x_window_root_get(win);
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
+ reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(&ev, 0, sizeof(xcb_button_press_event_t));
+
+ ev.response_type = XCB_BUTTON_PRESS;
+ ev.event = win;
+ ev.child = win;
+ ev.root = root;
+ ev.event_x = x;
+ ev.event_y = y;
+ ev.same_screen = 1;
+ ev.state = 1 << b;
+ ev.detail = b; // xcb uses detail for button
+ ev.root_x = reply->dst_x;
+ ev.root_y = reply->dst_y;
+ ev.time = ecore_x_current_time_get();
+ free(reply);
+
+ vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
+ XCB_EVENT_MASK_BUTTON_PRESS, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b)
+{
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *reply;
+ xcb_button_release_event_t ev;
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+ Ecore_X_Window root = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ecore_x_window_root_get(win);
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
+ reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(&ev, 0, sizeof(xcb_button_release_event_t));
+
+ ev.response_type = XCB_BUTTON_RELEASE;
+ ev.event = win;
+ ev.child = win;
+ ev.root = root;
+ ev.event_x = x;
+ ev.event_y = y;
+ ev.same_screen = 1;
+ ev.state = 0;
+ ev.root_x = reply->dst_x;
+ ev.root_y = reply->dst_y;
+ ev.detail = b; // xcb uses detail for button
+ ev.time = ecore_x_current_time_get();
+ free(reply);
+
+ vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
+ XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y)
+{
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *reply;
+ xcb_motion_notify_event_t ev;
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+ Ecore_X_Window root = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ecore_x_window_root_get(win);
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
+ reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(&ev, 0, sizeof(xcb_motion_notify_event_t));
+
+ ev.response_type = XCB_MOTION_NOTIFY;
+ ev.event = win;
+ ev.child = win;
+ ev.root = root;
+ ev.event_x = x;
+ ev.event_y = y;
+ ev.same_screen = 1;
+ ev.state = 0;
+ ev.detail = 0; // xcb uses 'detail' for is_hint
+ ev.root_x = reply->dst_x;
+ ev.root_y = reply->dst_y;
+ ev.time = ecore_x_current_time_get();
+ free(reply);
+
+ vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
+ XCB_EVENT_MASK_POINTER_MOTION, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y)
+{
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *reply;
+ xcb_enter_notify_event_t ev;
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+ Ecore_X_Window root = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ecore_x_window_root_get(win);
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
+ reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(&ev, 0, sizeof(xcb_enter_notify_event_t));
+
+ ev.response_type = XCB_ENTER_NOTIFY;
+ ev.event = win;
+ ev.child = win;
+ ev.root = root;
+ ev.event_x = x;
+ ev.event_y = y;
+ ev.same_screen_focus = 1;
+ ev.mode = XCB_NOTIFY_MODE_NORMAL;
+ ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR;
+ /* ev.focus = 0; */
+ ev.state = 0;
+ ev.root_x = reply->dst_x;
+ ev.root_y = reply->dst_y;
+ ev.time = ecore_x_current_time_get();
+ free(reply);
+
+ vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
+ XCB_EVENT_MASK_ENTER_WINDOW, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_out_send(Ecore_X_Window win, int x, int y)
+{
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *reply;
+ xcb_leave_notify_event_t ev;
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+ Ecore_X_Window root = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ecore_x_window_root_get(win);
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
+ reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(&ev, 0, sizeof(xcb_leave_notify_event_t));
+
+ ev.response_type = XCB_LEAVE_NOTIFY;
+ ev.event = win;
+ ev.child = win;
+ ev.root = root;
+ ev.event_x = x;
+ ev.event_y = y;
+ ev.same_screen_focus = 1;
+ ev.mode = XCB_NOTIFY_MODE_NORMAL;
+ ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR;
+ /* ev.focus = 0; */
+ ev.state = 0;
+ ev.root_x = reply->dst_x;
+ ev.root_y = reply->dst_y;
+ ev.time = ecore_x_current_time_get();
+ free(reply);
+
+ vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
+ XCB_EVENT_MASK_LEAVE_WINDOW, (const char *)&ev);
+
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_keyboard_grab(Ecore_X_Window win)
+{
+ xcb_grab_keyboard_cookie_t cookie;
+ xcb_grab_keyboard_reply_t *reply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie =
+ xcb_grab_keyboard_unchecked(_ecore_xcb_conn, 0, win, XCB_CURRENT_TIME,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ reply = xcb_grab_keyboard_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+ free(reply);
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_keyboard_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_ungrab_keyboard(_ecore_xcb_conn, XCB_CURRENT_TIME);
+}
+
+EAPI void
+ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y)
+{
+ xcb_query_pointer_cookie_t cookie;
+ xcb_query_pointer_reply_t *reply;
+
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+// if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ if (x) *x = -1;
+ if (y) *y = -1;
+
+ cookie = xcb_query_pointer_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_query_pointer_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ if (x) *x = reply->win_x;
+ if (y) *y = reply->win_y;
+ free(reply);
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold)
+{
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ vcookie =
+ xcb_change_pointer_control_checked(_ecore_xcb_conn,
+ accel_num, accel_denom, threshold,
+ 1, 1);
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold)
+{
+ xcb_get_pointer_control_cookie_t cookie;
+ xcb_get_pointer_control_reply_t *reply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (accel_num) *accel_num = 0;
+ if (accel_denom) *accel_denom = 0;
+ if (threshold) *threshold = 0;
+
+ cookie = xcb_get_pointer_control_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_pointer_control_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ if (accel_num) *accel_num = reply->acceleration_numerator;
+ if (accel_denom) *accel_denom = reply->acceleration_denominator;
+ if (threshold) *threshold = reply->threshold;
+ free(reply);
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_mapping_set(unsigned char *map, int nmap)
+{
+ xcb_set_pointer_mapping_cookie_t cookie;
+ xcb_set_pointer_mapping_reply_t *reply;
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_set_pointer_mapping_unchecked(_ecore_xcb_conn, nmap, map);
+ reply = xcb_set_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ if (reply->status == XCB_MAPPING_STATUS_SUCCESS)
+ ret = EINA_TRUE;
+
+ free(reply);
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_mapping_get(unsigned char *map, int nmap)
+{
+ xcb_get_pointer_mapping_cookie_t cookie;
+ xcb_get_pointer_mapping_reply_t *reply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (map) *map = 0;
+ nmap = 0;
+
+ cookie = xcb_get_pointer_mapping_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ nmap = xcb_get_pointer_mapping_map_length(reply);
+ if (nmap <= 0)
+ {
+ free(reply);
+ return EINA_FALSE;
+ }
+
+ if (map)
+ {
+ uint8_t *tmp;
+ int i = 0;
+
+ tmp = xcb_get_pointer_mapping_map(reply);
+ for (i = 0; i < nmap; i++)
+ map[i] = tmp[i];
+ }
+
+ free(reply);
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_grab(Ecore_X_Window win)
+{
+ xcb_grab_pointer_cookie_t cookie;
+ xcb_grab_pointer_reply_t *reply;
+ uint16_t mask;
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION);
+
+ cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask,
+ XCB_GRAB_MODE_ASYNC,
+ XCB_GRAB_MODE_ASYNC,
+ XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
+ reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE;
+
+ free(reply);
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_confine_grab(Ecore_X_Window win)
+{
+ xcb_grab_pointer_cookie_t cookie;
+ xcb_grab_pointer_reply_t *reply;
+ uint16_t mask;
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION);
+
+ cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask,
+ XCB_GRAB_MODE_ASYNC,
+ XCB_GRAB_MODE_ASYNC,
+ win, XCB_NONE, XCB_CURRENT_TIME);
+ reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE;
+
+ free(reply);
+ return ret;
+}
+
+EAPI void
+ecore_x_pointer_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME);
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_warp(Ecore_X_Window win, int x, int y)
+{
+ xcb_void_cookie_t vcookie;
+ xcb_generic_error_t *err;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ vcookie =
+ xcb_warp_pointer_checked(_ecore_xcb_conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
+ err = xcb_request_check(_ecore_xcb_conn, vcookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+/**
+ * Invoke the standard system beep to alert users
+ *
+ * @param percent The volume at which the bell rings. Must be in the range
+ * [-100,+100]. If percent >= 0, the final volume will be:
+ * base - [(base * percent) / 100] + percent
+ * Otherwise, it's calculated as:
+ * base + [(base * percent) / 100]
+ * where @c base is the bell's base volume as set by XChangeKeyboardControl(3).
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_bell(int percent)
+{
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+
+ CHECK_XCB_CONN;
+
+ // FIXME: Use unchecked version after development is ironed out
+ cookie = xcb_bell_checked(_ecore_xcb_conn, percent);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_display_size_get(Ecore_X_Display *dsp EINA_UNUSED, int *w, int *h)
+{
+ xcb_screen_t *screen;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ /* grab the default screen */
+ screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
+ if (w) *w = screen->width_in_pixels;
+ if (h) *h = screen->height_in_pixels;
+}
+
+EAPI unsigned long
+ecore_x_display_black_pixel_get(Ecore_X_Display *dsp EINA_UNUSED)
+{
+ xcb_screen_t *screen;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ /* grab the default screen */
+ screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
+ return screen->black_pixel;
+}
+
+EAPI unsigned long
+ecore_x_display_white_pixel_get(Ecore_X_Display *dsp EINA_UNUSED)
+{
+ xcb_screen_t *screen;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ /* grab the default screen */
+ screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
+ return screen->white_pixel;
+}
+
+EAPI void
+ecore_x_pointer_last_xy_get(int *x, int *y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (x) *x = _ecore_xcb_event_last_root_x;
+ if (y) *y = _ecore_xcb_event_last_root_y;
+}
+
+EAPI void
+ecore_x_focus_reset(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_set_input_focus(_ecore_xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ XCB_CURRENT_TIME);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_events_allow_all(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME);
+// ecore_x_flush();
+}
+
+/**
+ * Kill a specific client
+ *
+ * You can kill a specific client owning window @p win
+ *
+ * @param win Window of the client to be killed
+ */
+EAPI void
+ecore_x_kill(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_kill_client(_ecore_xcb_conn, win);
+// ecore_x_flush();
+}
+
+/**
+ * Kill all clients with subwindows under a given window.
+ *
+ * You can kill all clients connected to the X server by using
+ * @ref ecore_x_window_root_list to get a list of root windows, and
+ * then passing each root window to this function.
+ *
+ * @param root The window whose children will be killed.
+ */
+EAPI void
+ecore_x_killall(Ecore_X_Window root)
+{
+ int screens = 0, i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ ecore_x_grab();
+
+ screens = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem;
+
+ /* Traverse window tree starting from root, and drag each
+ * before the firing squad */
+ for (i = 0; i < screens; ++i)
+ {
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+
+ cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ xcb_window_t *wins = NULL;
+ int tree_c_len, j = 0;
+
+ wins = xcb_query_tree_children(reply);
+ tree_c_len = xcb_query_tree_children_length(reply);
+ for (j = 0; j < tree_c_len; j++)
+ xcb_kill_client(_ecore_xcb_conn, wins[j]);
+ free(reply);
+ }
+ }
+
+ ecore_x_ungrab();
+ ecore_x_sync(); // needed
+}
+
+/**
+ * Return the screen DPI
+ *
+ * This is a simplistic call to get DPI. It does not account for differing
+ * DPI in the x amd y axes nor does it account for multihead or xinerama and
+ * xrander where different parts of the screen may have differen DPI etc.
+ *
+ * @return the general screen DPI (dots/pixels per inch).
+ */
+EAPI int
+ecore_x_dpi_get(void)
+{
+ uint16_t mw = 0, w = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ mw = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_millimeters;
+ if (mw <= 0) return 75;
+ w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels;
+ return (((w * 254) / mw) + 5) / 10;
+}
+
+/**
+ * @defgroup Ecore_X_Display_Attr_Group X Display Attributes
+ *
+ * Functions that set and retrieve X display attributes.
+ */
+
+/**
+ * Retrieves the Ecore_X_Display handle used for the current X connection.
+ * @return The current X display.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI Ecore_X_Display *
+ecore_x_display_get(void)
+{
+ char *gl = NULL;
+
+ CHECK_XCB_CONN;
+
+ /* if we have the 'dont use xlib' env var, then we are not using
+ * XLib and thus cannot return a real XDisplay.
+ *
+ * NB: This may break EFL in some places and needs lots of testing !!! */
+ if ((gl = getenv("ECORE_X_NO_XLIB")))
+ return (Ecore_X_Display *)_ecore_xcb_conn;
+ else /* we can safely return an XDisplay var */
+ return (Ecore_X_Display *)_ecore_xcb_display;
+}
+
+/**
+ * Retrieves the X display file descriptor.
+ * @return The current X display file descriptor.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI int
+ecore_x_fd_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+ return xcb_get_file_descriptor(_ecore_xcb_conn);
+}
+
+EAPI void
+ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int type, void *event),
+ void *data)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_window_grab_replay_func = func;
+ _ecore_xcb_window_grab_replay_data = data;
+}
+
+/**
+ * Retrieves the size of an Ecore_X_Screen.
+ * @param screen the handle to the screen to query.
+ * @param w where to return the width. May be NULL. Returns 0 on errors.
+ * @param h where to return the height. May be NULL. Returns 0 on errors.
+ * @ingroup Ecore_X_Display_Attr_Group
+ * @see ecore_x_default_screen_get()
+ *
+ * @since 1.1
+ */
+EAPI void
+ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h)
+{
+ xcb_screen_t *s;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (!(s = (xcb_screen_t *)screen)) return;
+ if (w) *w = s->width_in_pixels;
+ if (h) *h = s->height_in_pixels;
+}
+
+/**
+ * Retrieves the count of screens.
+ *
+ * @return The count of screens.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI int
+ecore_x_screen_count_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ return xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn));
+}
+
+/**
+ * Retrieves the index number of the given screen.
+ *
+ * @param screen The screen for which index will be gotten.
+ * @return The index number of the screen.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI int
+ecore_x_screen_index_get(const Ecore_X_Screen *screen)
+{
+ xcb_screen_iterator_t iter;
+ int i = 0;
+
+ CHECK_XCB_CONN;
+
+ iter =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ for (; iter.rem; xcb_screen_next(&iter))
+ {
+ if (iter.data == (xcb_screen_t *)screen)
+ return i;
+ i++;
+ }
+
+ return 0;
+}
+
+/**
+ * Retrieves the screen based on index number.
+ *
+ * @param idx The index that will be used to retrieve the screen.
+ * @return The Ecore_X_Screen at this index.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI Ecore_X_Screen *
+ecore_x_screen_get(int idx)
+{
+ xcb_screen_iterator_t iter;
+ int i = 0;
+
+ CHECK_XCB_CONN;
+
+ iter =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
+ if (i == idx) return iter.data;
+
+ return NULL;
+}
+
+EAPI unsigned int
+ecore_x_visual_id_get(Ecore_X_Visual visual)
+{
+ return ((xcb_visualtype_t *)visual)->visual_id;
+}
+
+/**
+ * Retrieve the default Visual.
+ *
+ * @param disp The Display to get the Default Visual from
+ * @param screen The Screen.
+ *
+ * @return The default visual.
+ * @since 1.1.0
+ */
+EAPI Ecore_X_Visual
+ecore_x_default_visual_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
+{
+ xcb_screen_t *s;
+ xcb_depth_iterator_t diter;
+ xcb_visualtype_iterator_t viter;
+
+ CHECK_XCB_CONN;
+
+ s = (xcb_screen_t *)screen;
+ diter = xcb_screen_allowed_depths_iterator(s);
+ for (; diter.rem; xcb_depth_next(&diter))
+ {
+ viter = xcb_depth_visuals_iterator(diter.data);
+ for (; viter.rem; xcb_visualtype_next(&viter))
+ {
+ if (viter.data->visual_id == s->root_visual)
+ return viter.data;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Retrieve the default Colormap.
+ *
+ * @param disp The Display to get the Default Colormap from
+ * @param screen The Screen.
+ *
+ * @return The default colormap.
+ * @since 1.1.0
+ */
+EAPI Ecore_X_Colormap
+ecore_x_default_colormap_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
+{
+ xcb_screen_t *s;
+
+ s = (xcb_screen_t *)screen;
+ return s->default_colormap;
+}
+
+/**
+ * Retrieve the default depth.
+ *
+ * @param disp The Display to get the Default Depth from
+ * @param screen The Screen.
+ *
+ * @return The default depth.
+ * @since 1.1.0
+ */
+EAPI int
+ecore_x_default_depth_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
+{
+ xcb_screen_t *s;
+
+ s = (xcb_screen_t *)screen;
+ return s->root_depth;
+}
+
+EAPI void
+ecore_x_xkb_select_group(int group)
+{
+ // XXX: implement me */
+}
+
+/**
+ * Sets the timeout for a double and triple clicks to be flagged.
+ *
+ * This sets the time between clicks before the double_click flag is
+ * set in a button down event. If 3 clicks occur within double this
+ * time, the triple_click flag is also set.
+ *
+ * @param t The time in seconds
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI void
+ecore_x_double_click_time_set(double t)
+{
+ if (t < 0.0) t = 0.0;
+ _ecore_xcb_double_click_time = t;
+}
+
+/**
+ * Retrieves the double and triple click flag timeout.
+ *
+ * See @ref ecore_x_double_click_time_set for more information.
+ *
+ * @return The timeout for double clicks in seconds.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI double
+ecore_x_double_click_time_get(void)
+{
+ return _ecore_xcb_double_click_time;
+}
+
+/* local function prototypes */
+static int
+_ecore_xcb_shutdown(Eina_Bool close_display)
+{
+ if (--_ecore_xcb_init_count != 0)
+ return _ecore_xcb_init_count;
+
+ if (!_ecore_xcb_conn)
+ return _ecore_xcb_init_count;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ ecore_idle_enterer_del(_ecore_xcb_idle_enterer);
+ _ecore_xcb_idle_enterer = NULL;
+
+ if (_ecore_xcb_fd_handler)
+ ecore_main_fd_handler_del(_ecore_xcb_fd_handler);
+
+ /* disconnect from display server */
+ if (close_display)
+ xcb_disconnect(_ecore_xcb_conn);
+ else
+ {
+ close(xcb_get_file_descriptor(_ecore_xcb_conn));
+ _ecore_xcb_conn = NULL;
+ }
+
+ /* shutdown events */
+ _ecore_xcb_events_shutdown();
+
+ /* shutdown input extension */
+ _ecore_xcb_input_shutdown();
+
+ /* shutdown gesture extension */
+ _ecore_xcb_gesture_shutdown();
+
+ /* shutdown selection */
+ _ecore_xcb_selection_shutdown();
+
+ /* shutdown dnd */
+ _ecore_xcb_dnd_shutdown();
+
+ /* shutdown netwm */
+ ecore_x_netwm_shutdown();
+
+ /* shutdown keymap */
+ _ecore_xcb_keymap_shutdown();
+
+ /* shutdown ecore_event */
+ ecore_event_shutdown();
+
+ /* shutdown ecore */
+ ecore_shutdown();
+
+ /* unregister log domain */
+ eina_log_domain_unregister(_ecore_xcb_log_dom);
+ _ecore_xcb_log_dom = -1;
+
+ /* shutdown eina */
+ eina_shutdown();
+
+ return _ecore_xcb_init_count;
+}
+
+static Eina_Bool
+_ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ xcb_connection_t *conn;
+ xcb_generic_event_t *ev = NULL;
+
+ conn = (xcb_connection_t *)data;
+
+ if (_ecore_xcb_event_buffered)
+ {
+ _ecore_xcb_events_handle(_ecore_xcb_event_buffered);
+ free(_ecore_xcb_event_buffered);
+ _ecore_xcb_event_buffered = NULL;
+ }
+
+// xcb_flush(conn);
+
+ while ((ev = xcb_poll_for_event(conn)))
+ {
+ /* NB: Ecore Xlib uses filterevent for xim, but xcb does not support
+ * xim, so no need for it here */
+
+ /* check for errors first */
+ if (xcb_connection_has_error(conn))
+ {
+ xcb_generic_error_t *err;
+
+ err = (xcb_generic_error_t *)ev;
+ _ecore_xcb_io_error_handle(err);
+ }
+ else
+ {
+ /* FIXME: Filter event for XIM */
+ _ecore_xcb_events_handle(ev);
+ free(ev);
+ }
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ xcb_connection_t *conn;
+ xcb_generic_event_t *ev = NULL;
+
+ conn = (xcb_connection_t *)data;
+ ev = xcb_poll_for_event(conn);
+ if (ev)
+ {
+ /* check for errors first */
+ if (xcb_connection_has_error(conn))
+ {
+ xcb_generic_error_t *err;
+
+ err = (xcb_generic_error_t *)ev;
+ _ecore_xcb_io_error_handle(err);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ _ecore_xcb_event_buffered = ev;
+ return ECORE_CALLBACK_RENEW;
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_xcb_idle_enter(void *data EINA_UNUSED)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_flush(_ecore_xcb_conn);
+ return ECORE_CALLBACK_RENEW;
+}
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_atoms.c b/src/lib/ecore_x/xcb/ecore_xcb_atoms.c
new file mode 100644
index 0000000000..c8c217eec7
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_atoms.c
@@ -0,0 +1,149 @@
+#include "ecore_xcb_private.h"
+#include "ecore_x_atoms_decl.h"
+
+/* NB: Increment if you add new atoms */
+#define ECORE_X_ATOMS_COUNT 199
+
+/* local function prototypes */
+
+/* local variables */
+static xcb_intern_atom_cookie_t cookies[ECORE_X_ATOMS_COUNT];
+
+void
+_ecore_xcb_atoms_init(void)
+{
+ int i = 0, num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ num = (sizeof(atom_items) / sizeof(Atom_Item));
+ for (i = 0; i < num; i++)
+ {
+ cookies[i] =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
+ strlen(atom_items[i].name), atom_items[i].name);
+ }
+}
+
+void
+_ecore_xcb_atoms_finalize(void)
+{
+ int i = 0, num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ num = (sizeof(atom_items) / sizeof(Atom_Item));
+ for (i = 0; i < num; i++)
+ {
+ xcb_intern_atom_reply_t *reply = NULL;
+
+ if (!(reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], 0)))
+ continue;
+ *(atom_items[i].atom) = reply->atom;
+ free(reply);
+ }
+}
+
+/**
+ * @defgroup Ecore_X_Atom_Group XCB Atom Functions
+ *
+ * Functions that operate on atoms
+ */
+
+/**
+ * Retrieves the atom value associated to a name.
+ *
+ * @param name Unused.
+ * @return Associated atom value.
+ *
+ * Retrieves the atom value associated to a name. The reply is the
+ * returned value of the function ecore_xcb_intern_atom_reply(). If
+ * @p reply is @c NULL, the NULL atom is returned. Otherwise, the atom
+ * associated to the name is returned.
+ *
+ * @ingroup Ecore_X_Atom_Group
+ */
+EAPI Ecore_X_Atom
+ecore_x_atom_get(const char *name)
+{
+ xcb_intern_atom_cookie_t cookie;
+ xcb_intern_atom_reply_t *reply;
+ Ecore_X_Atom a;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(name), name);
+ reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return XCB_ATOM_NONE;
+ a = reply->atom;
+ free(reply);
+ return a;
+}
+
+/**
+ * Retrieves the name of the given atom.
+ *
+ * @param atom
+ * @return The name of the atom.
+ *
+ * @ingroup Ecore_X_Atom_Group
+ */
+EAPI char *
+ecore_x_atom_name_get(Ecore_X_Atom atom)
+{
+ xcb_get_atom_name_cookie_t cookie;
+ xcb_get_atom_name_reply_t *reply;
+ char *name;
+ int len = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_atom_name_unchecked(_ecore_xcb_conn, atom);
+ reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+ len = xcb_get_atom_name_name_length(reply);
+ name = (char *)malloc(sizeof(char) * (len + 1));
+ if (!name)
+ {
+ free(reply);
+ return NULL;
+ }
+ memcpy(name, xcb_get_atom_name_name(reply), len);
+ name[len] = '\0';
+
+ free(reply);
+ return name;
+}
+
+EAPI void
+ecore_x_atoms_get(const char **names,
+ int num,
+ Ecore_X_Atom *atoms)
+{
+ xcb_intern_atom_cookie_t cookies[num];
+ int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ for (i = 0; i < num; i++)
+ {
+ cookies[i] =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 0,
+ strlen(names[i]), names[i]);
+ }
+ for (i = 0; i < num; i++)
+ {
+ xcb_intern_atom_reply_t *reply = NULL;
+
+ if (!(reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], 0)))
+ continue;
+ atoms[i] = reply->atom;
+ free(reply);
+ }
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_composite.c b/src/lib/ecore_x/xcb/ecore_xcb_composite.c
new file mode 100644
index 0000000000..0d3b44e4aa
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_composite.c
@@ -0,0 +1,290 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_COMPOSITE
+# include <xcb/composite.h>
+#endif
+
+/* local variables */
+static Eina_Bool _composite_avail = EINA_FALSE;
+
+void
+_ecore_xcb_composite_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_COMPOSITE
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_composite_id);
+#endif
+}
+
+void
+_ecore_xcb_composite_finalize(void)
+{
+#ifdef ECORE_XCB_COMPOSITE
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_COMPOSITE
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_composite_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_composite_query_version_cookie_t cookie;
+ xcb_composite_query_version_reply_t *reply;
+
+ cookie =
+ xcb_composite_query_version_unchecked(_ecore_xcb_conn,
+ XCB_COMPOSITE_MAJOR_VERSION,
+ XCB_COMPOSITE_MINOR_VERSION);
+ reply =
+ xcb_composite_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+// if ((reply->major_version >= XCB_COMPOSITE_MAJOR_VERSION) &&
+ if (reply->minor_version >= XCB_COMPOSITE_MINOR_VERSION)
+ {
+# ifdef ECORE_XCB_RENDER
+ if (_ecore_xcb_render_avail_get())
+ {
+# ifdef ECORE_XCB_XFIXES
+ if (_ecore_xcb_xfixes_avail_get())
+ _composite_avail = EINA_TRUE;
+# endif
+ }
+# endif
+ }
+
+ free(reply);
+ }
+ }
+#endif
+}
+
+/**
+ * @defgroup Ecore_X_Composite_Group X Composite Extension Functions
+ *
+ * Functions related to the X Composite Extension
+ */
+
+/**
+ * Return whether the Composite Extension is available
+ *
+ * @return @c EINA_TRUE is the Composite Extension is available, @c EINA_FALSE
+ * if not.
+ *
+ * @ingroup Ecore_X_Composite_Group
+ */
+EAPI Eina_Bool
+ecore_x_composite_query(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _composite_avail;
+}
+
+EAPI void
+ecore_x_composite_redirect_window(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_COMPOSITE
+ uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = XCB_COMPOSITE_REDIRECT_MANUAL;
+ break;
+ }
+ xcb_composite_redirect_window(_ecore_xcb_conn, win, update);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_composite_redirect_subwindows(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_COMPOSITE
+ uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = XCB_COMPOSITE_REDIRECT_MANUAL;
+ break;
+ }
+ xcb_composite_redirect_subwindows(_ecore_xcb_conn, win, update);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_composite_unredirect_window(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_COMPOSITE
+ uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = XCB_COMPOSITE_REDIRECT_MANUAL;
+ break;
+ }
+ xcb_composite_unredirect_window(_ecore_xcb_conn, win, update);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_composite_unredirect_subwindows(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_COMPOSITE
+ uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = XCB_COMPOSITE_REDIRECT_AUTOMATIC;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = XCB_COMPOSITE_REDIRECT_MANUAL;
+ break;
+ }
+ xcb_composite_unredirect_subwindows(_ecore_xcb_conn, win, update);
+// ecore_x_flush();
+#endif
+}
+
+EAPI Ecore_X_Pixmap
+ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win)
+{
+#ifdef ECORE_XCB_COMPOSITE
+ Ecore_X_Pixmap pmap = XCB_NONE;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return XCB_NONE;
+
+#ifdef ECORE_XCB_COMPOSITE
+ pmap = xcb_generate_id(_ecore_xcb_conn);
+ xcb_composite_name_window_pixmap(_ecore_xcb_conn, win, pmap);
+// ecore_x_flush();
+#endif
+
+ return pmap;
+}
+
+EAPI void
+ecore_x_composite_window_events_disable(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_SHAPE
+ ecore_x_window_shape_input_rectangle_set(win, -1, -1, 1, 1);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_composite_window_events_enable(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_SHAPE
+ ecore_x_window_shape_input_rectangle_set(win, 0, 0, 65535, 65535);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+#endif
+}
+
+EAPI Ecore_X_Window
+ecore_x_composite_render_window_enable(Ecore_X_Window root)
+{
+ Ecore_X_Window win = 0;
+#ifdef ECORE_XCB_COMPOSITE
+ xcb_composite_get_overlay_window_cookie_t cookie;
+ xcb_composite_get_overlay_window_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return 0;
+
+#ifdef ECORE_XCB_COMPOSITE
+ cookie = xcb_composite_get_overlay_window_unchecked(_ecore_xcb_conn, root);
+ reply =
+ xcb_composite_get_overlay_window_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return win;
+
+ win = reply->overlay_win;
+ free(reply);
+
+ ecore_x_composite_window_events_disable(win);
+// ecore_x_flush();
+#endif
+
+ return win;
+}
+
+EAPI void
+ecore_x_composite_render_window_disable(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_composite_avail) return;
+
+#ifdef ECORE_XCB_COMPOSITE
+ xcb_composite_release_overlay_window(_ecore_xcb_conn, win);
+// ecore_x_flush();
+#endif
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_cursor.c b/src/lib/ecore_x/xcb/ecore_xcb_cursor.c
new file mode 100644
index 0000000000..755df04e4f
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_cursor.c
@@ -0,0 +1,400 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_CURSOR
+# include <xcb/render.h>
+# include <xcb/xcb_renderutil.h>
+#endif
+
+/* local function prototypes */
+#ifdef ECORE_XCB_CURSOR
+static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format_get(void);
+#endif
+static void _ecore_xcb_cursor_default_size_get(void);
+static void _ecore_xcb_cursor_dpi_size_get(void);
+static void _ecore_xcb_cursor_guess_size(void);
+#ifdef ECORE_XCB_CURSOR
+static Ecore_X_Cursor _ecore_xcb_cursor_image_load_cursor(xcb_image_t *img,
+ int hot_x,
+ int hot_y);
+#endif
+static void _ecore_xcb_cursor_image_destroy(xcb_image_t *img);
+
+/* local variables */
+static int _ecore_xcb_cursor_size = 0;
+static Eina_Bool _ecore_xcb_cursor = EINA_FALSE;
+#ifdef ECORE_XCB_CURSOR
+static uint32_t _ecore_xcb_cursor_format_id = 0;
+// static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format = NULL;
+#endif
+
+void
+_ecore_xcb_cursor_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* NB: No-op */
+}
+
+void
+_ecore_xcb_cursor_finalize(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_CURSOR
+ _ecore_xcb_cursor = _ecore_xcb_render_argb_get();
+
+ /* find render pict format */
+ if (_ecore_xcb_cursor_format_id <= 0)
+ _ecore_xcb_cursor_format_id = _ecore_xcb_cursor_format_get()->id;
+#endif
+
+ /* try to grab cursor size from XDefaults */
+ _ecore_xcb_cursor_default_size_get();
+
+ /* if that failed, try to get it from Xft Dpi setting */
+ if (_ecore_xcb_cursor_size == 0)
+ _ecore_xcb_cursor_dpi_size_get();
+
+ /* if that failed, try to guess from display size */
+ if (_ecore_xcb_cursor_size == 0)
+ _ecore_xcb_cursor_guess_size();
+
+ /* NB: Would normally add theme stuff here, but E cursor does not support
+ * xcursor themes. Delay parsing that stuff out until such time if/when the
+ * user selects to use X Cursor, rather than E cursor */
+}
+
+EAPI Eina_Bool
+ecore_x_cursor_color_supported_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_cursor;
+}
+
+EAPI Ecore_X_Cursor
+ecore_x_cursor_new(Ecore_X_Window win,
+ int *pixels,
+ int w,
+ int h,
+ int hot_x,
+ int hot_y)
+{
+ Ecore_X_Cursor cursor = 0;
+ xcb_image_t *img;
+
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_CURSOR
+ if (_ecore_xcb_cursor)
+ {
+ img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 32, NULL, (w * h * sizeof(int)),
+ (uint8_t *)pixels);
+ cursor = _ecore_xcb_cursor_image_load_cursor(img, hot_x, hot_y);
+ _ecore_xcb_cursor_image_destroy(img);
+ return cursor;
+ }
+ else
+#endif
+ {
+ Ecore_X_GC gc;
+ xcb_pixmap_t pmap, mask;
+ uint32_t *pix;
+ uint8_t fr = 0x00, fg = 0x00, fb = 0x00;
+ uint8_t br = 0xff, bg = 0xff, bb = 0xff;
+ uint32_t brightest = 0, darkest = 255 * 3;
+ uint16_t x, y;
+ const uint32_t dither[2][2] =
+ {
+ {0, 2},
+ {3, 1}
+ };
+
+ img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ 1, NULL, ~0, NULL);
+ if (img->data) free(img->data);
+ img->data = malloc(img->size);
+
+ pmap = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, 1, pmap, win, w, h);
+ mask = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, 1, mask, win, w, h);
+
+ pix = (uint32_t *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ uint8_t r, g, b, a;
+
+ a = (pix[0] >> 24) & 0xff;
+ r = (pix[0] >> 16) & 0xff;
+ g = (pix[0] >> 8) & 0xff;
+ b = (pix[0]) & 0xff;
+ if (a > 0)
+ {
+ if ((uint32_t)(r + g + b) > brightest)
+ {
+ brightest = r + g + b;
+ br = r;
+ bg = g;
+ bb = b;
+ }
+
+ if ((uint32_t)(r + g + b) < darkest)
+ {
+ darkest = r + g + b;
+ fr = r;
+ fg = g;
+ fb = b;
+ }
+ }
+ pix++;
+ }
+ }
+
+ pix = (uint32_t *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ uint32_t v;
+ uint8_t r, g, b;
+ int32_t d1, d2;
+
+ r = (pix[0] >> 16) & 0xff;
+ g = (pix[0] >> 8) & 0xff;
+ b = (pix[0]) & 0xff;
+ d1 =
+ ((r - fr) * (r - fr)) +
+ ((g - fg) * (g - fg)) +
+ ((b - fb) * (b - fb));
+ d2 =
+ ((r - br) * (r - br)) +
+ ((g - bg) * (g - bg)) +
+ ((b - bb) * (b - bb));
+ if (d1 + d2)
+ {
+ v = (((d2 * 255) / (d1 + d2)) * 5) / 256;
+ if (v > dither[x & 0x1][y & 0x1])
+ v = 1;
+ else
+ v = 0;
+ }
+ else
+ v = 0;
+
+ xcb_image_put_pixel(img, x, y, v);
+ pix++;
+ }
+ }
+
+ gc = ecore_x_gc_new(pmap, 0, NULL);
+ xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc, w, h,
+ 0, 0, 0, img->depth, img->size, img->data);
+ ecore_x_gc_free(gc);
+
+ pix = (uint32_t *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ uint32_t v;
+
+ v = (((pix[0] >> 24) & 0xff) * 5) / 256;
+ if (v > dither[x & 0x1][y & 0x1])
+ v = 1;
+ else
+ v = 0;
+
+ xcb_image_put_pixel(img, x, y, v);
+ pix++;
+ }
+ }
+
+ gc = ecore_x_gc_new(mask, 0, NULL);
+ xcb_put_image(_ecore_xcb_conn, img->format, mask, gc, w, h,
+ 0, 0, 0, img->depth, img->size, img->data);
+ ecore_x_gc_free(gc);
+
+ if (img->data) free(img->data);
+ _ecore_xcb_cursor_image_destroy(img);
+
+ cursor = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_cursor(_ecore_xcb_conn, cursor, pmap, mask,
+ fr << 8 | fr, fg << 8 | fg, fb << 8 | fb,
+ br << 8 | br, bg << 8 | bg, bb << 8 | bb,
+ hot_x, hot_y);
+
+ xcb_free_pixmap(_ecore_xcb_conn, pmap);
+ xcb_free_pixmap(_ecore_xcb_conn, mask);
+
+ return cursor;
+ }
+
+ return 0;
+}
+
+EAPI void
+ecore_x_cursor_free(Ecore_X_Cursor c)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_free_cursor(_ecore_xcb_conn, c);
+}
+
+/*
+ * Returns the cursor for the given shape.
+ * Note that the return value must not be freed with
+ * ecore_x_cursor_free()!
+ */
+EAPI Ecore_X_Cursor
+ecore_x_cursor_shape_get(int shape)
+{
+ Ecore_X_Cursor cursor = 0;
+ xcb_font_t font;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ font = xcb_generate_id(_ecore_xcb_conn);
+ xcb_open_font(_ecore_xcb_conn, font, strlen("cursor"), "cursor");
+
+ cursor = xcb_generate_id(_ecore_xcb_conn);
+ /* FIXME: Add request check ?? */
+ xcb_create_glyph_cursor(_ecore_xcb_conn, cursor, font, font,
+ shape, shape + 1, 0, 0, 0, 65535, 65535, 65535);
+
+ xcb_close_font(_ecore_xcb_conn, font);
+ return cursor;
+}
+
+EAPI void
+ecore_x_cursor_size_set(int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_cursor_size = size;
+ /* NB: May need to adjust size of current cursors here */
+}
+
+EAPI int
+ecore_x_cursor_size_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_cursor_size;
+}
+
+/* local functions */
+#ifdef ECORE_XCB_CURSOR
+static xcb_render_pictforminfo_t *
+_ecore_xcb_cursor_format_get(void)
+{
+ const xcb_render_query_pict_formats_reply_t *reply;
+ xcb_render_pictforminfo_t *ret = NULL;
+
+ CHECK_XCB_CONN;
+
+ reply = xcb_render_util_query_formats(_ecore_xcb_conn);
+ if (reply)
+ ret = xcb_render_util_find_standard_format(reply,
+ XCB_PICT_STANDARD_ARGB_32);
+
+ return ret;
+}
+
+#endif
+
+static void
+_ecore_xcb_cursor_default_size_get(void)
+{
+ char *s = NULL;
+ int v = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ s = getenv("XCURSOR_SIZE");
+ if (!s)
+ {
+ _ecore_xcb_xdefaults_init();
+ v = _ecore_xcb_xdefaults_int_get("Xcursor", "size");
+ _ecore_xcb_xdefaults_shutdown();
+ }
+ else
+ v = atoi(s);
+ if (v) _ecore_xcb_cursor_size = ((v * 16) / 72);
+}
+
+static void
+_ecore_xcb_cursor_dpi_size_get(void)
+{
+ int v = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_xdefaults_init();
+ v = _ecore_xcb_xdefaults_int_get("Xft", "dpi");
+ if (v) _ecore_xcb_cursor_size = ((v * 16) / 72);
+ _ecore_xcb_xdefaults_shutdown();
+}
+
+static void
+_ecore_xcb_cursor_guess_size(void)
+{
+ int w = 0, h = 0, s = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_screen_size_get(_ecore_xcb_screen, &w, &h);
+ if (h < w) s = h;
+ else s = w;
+ _ecore_xcb_cursor_size = (s / 48);
+}
+
+#ifdef ECORE_XCB_CURSOR
+static Ecore_X_Cursor
+_ecore_xcb_cursor_image_load_cursor(xcb_image_t *img,
+ int hot_x,
+ int hot_y)
+{
+ Ecore_X_Cursor cursor = 0;
+ Ecore_X_GC gc;
+ xcb_pixmap_t pmap;
+ xcb_render_picture_t pict;
+
+ CHECK_XCB_CONN;
+
+ pmap = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, img->depth, pmap,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ img->width, img->height);
+
+ gc = ecore_x_gc_new(pmap, 0, NULL);
+ xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc,
+ img->width, img->height, 0, 0, 0, img->depth,
+ img->size, img->data);
+ ecore_x_gc_free(gc);
+
+ pict = xcb_generate_id(_ecore_xcb_conn);
+ xcb_render_create_picture(_ecore_xcb_conn, pict, pmap,
+ _ecore_xcb_cursor_format_id, 0, NULL);
+ xcb_free_pixmap(_ecore_xcb_conn, pmap);
+
+ cursor = xcb_generate_id(_ecore_xcb_conn);
+ xcb_render_create_cursor(_ecore_xcb_conn, cursor, pict, hot_x, hot_y);
+ xcb_render_free_picture(_ecore_xcb_conn, pict);
+
+ return cursor;
+}
+
+#endif
+
+static void
+_ecore_xcb_cursor_image_destroy(xcb_image_t *img)
+{
+ CHECK_XCB_CONN;
+ if (img) xcb_image_destroy(img);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_damage.c b/src/lib/ecore_x/xcb/ecore_xcb_damage.c
new file mode 100644
index 0000000000..deb3b9cb49
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_damage.c
@@ -0,0 +1,155 @@
+#include "ecore_xcb_private.h"
+# ifdef ECORE_XCB_DAMAGE
+# include <xcb/damage.h>
+# endif
+
+/* local variables */
+static Eina_Bool _damage_avail = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_damage = -1;
+
+void
+_ecore_xcb_damage_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_DAMAGE
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_damage_id);
+#endif
+}
+
+void
+_ecore_xcb_damage_finalize(void)
+{
+#ifdef ECORE_XCB_DAMAGE
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_DAMAGE
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_damage_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_damage_query_version_cookie_t cookie;
+ xcb_damage_query_version_reply_t *reply;
+
+ cookie =
+ xcb_damage_query_version_unchecked(_ecore_xcb_conn,
+ XCB_DAMAGE_MAJOR_VERSION,
+ XCB_DAMAGE_MINOR_VERSION);
+ reply = xcb_damage_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ _damage_avail = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_damage_avail)
+ _ecore_xcb_event_damage = ext_reply->first_event;
+ }
+#endif
+}
+
+/**
+ * @defgroup Ecore_X_Damage_Group X Damage Extension Functions
+ *
+ * Functions related to the X Damage Extension.
+ */
+
+EAPI Eina_Bool
+ecore_x_damage_query(void)
+{
+ return _damage_avail;
+}
+
+/**
+ * Create a damage object
+ *
+ * @param drawable The drawable to monitor
+ * @param level The level of the damage report
+ * @return The damage object
+ *
+ * Creates a damage object to monitor changes to @p drawable,
+ * with the level @p level.
+ *
+ * @ingroup Ecore_X_Damage_Group
+ */
+EAPI Ecore_X_Damage
+ecore_x_damage_new(Ecore_X_Drawable drawable,
+ Ecore_X_Damage_Report_Level level)
+{
+ Ecore_X_Damage damage = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_damage_avail) return 0;
+
+#ifdef ECORE_XCB_DAMAGE
+ damage = xcb_generate_id(_ecore_xcb_conn);
+ xcb_damage_create(_ecore_xcb_conn, damage, drawable, level);
+// ecore_x_flush();
+#endif
+
+ return damage;
+}
+
+/**
+ * Destroy a damage object
+ *
+ * @param damage The damage object to destroy
+ *
+ * Destroys the damage object @p damage
+ *
+ * @ingroup Ecore_X_Damage_Group
+ */
+EAPI void
+ecore_x_damage_free(Ecore_X_Damage damage)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_damage_avail) return;
+
+#ifdef ECORE_XCB_DAMAGE
+ xcb_damage_destroy(_ecore_xcb_conn, damage);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Synchronously modifies the region
+ *
+ * @param damage The damage object to destroy
+ * @param repair The repair region
+ * @param parts The parts region
+ *
+ * Synchronously modifies the regions in the following manner:
+ * If @p repair is @c XCB_NONE:
+ * 1) parts = damage
+ * 2) damage = \<empty\>
+ * Otherwise:
+ * 1) parts = damage INTERSECT repair
+ * 2) damage = damage - parts
+ * 3) Generate DamageNotify for remaining damage areas
+ *
+ * @ingroup Ecore_X_Damage_Group
+ */
+EAPI void
+ecore_x_damage_subtract(Ecore_X_Damage damage,
+ Ecore_X_Region repair,
+ Ecore_X_Region parts)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_damage_avail) return;
+
+#ifdef ECORE_XCB_DAMAGE
+ xcb_damage_subtract(_ecore_xcb_conn, damage, repair, parts);
+// ecore_x_flush();
+#endif
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_dnd.c b/src/lib/ecore_x/xcb/ecore_xcb_dnd.c
new file mode 100644
index 0000000000..80ae6b4c5d
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_dnd.c
@@ -0,0 +1,688 @@
+#include "ecore_xcb_private.h"
+
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/* local structures */
+typedef struct _Version_Cache_Item
+{
+ Ecore_X_Window win;
+ int ver;
+} Version_Cache_Item;
+
+/* local function prototypes */
+static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target EINA_UNUSED,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *tprop EINA_UNUSED,
+ int *count EINA_UNUSED);
+
+/* local variables */
+static int _ecore_xcb_dnd_init_count = 0;
+static Ecore_X_DND_Source *_source = NULL;
+static Ecore_X_DND_Target *_target = NULL;
+static Version_Cache_Item *_version_cache = NULL;
+static int _version_cache_num = 0, _version_cache_alloc = 0;
+static void (*_posupdatecb)(void *,
+ Ecore_X_Xdnd_Position *);
+static void *_posupdatedata;
+
+/* external variables */
+EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
+EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
+EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
+EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
+EAPI int ECORE_X_EVENT_XDND_DROP = 0;
+EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
+
+void
+_ecore_xcb_dnd_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!_ecore_xcb_dnd_init_count)
+ {
+ _source = calloc(1, sizeof(Ecore_X_DND_Source));
+ if (!_source) return;
+ _source->version = ECORE_X_DND_VERSION;
+ _source->win = XCB_NONE;
+ _source->dest = XCB_NONE;
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ _source->prev.window = 0;
+
+ _target = calloc(1, sizeof(Ecore_X_DND_Target));
+ if (!_target)
+ {
+ free(_source);
+ _source = NULL;
+ return;
+ }
+ _target->win = XCB_NONE;
+ _target->source = XCB_NONE;
+ _target->state = ECORE_X_DND_TARGET_IDLE;
+
+ ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
+ }
+ _ecore_xcb_dnd_init_count++;
+}
+
+void
+_ecore_xcb_dnd_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_dnd_init_count--;
+ if (_ecore_xcb_dnd_init_count > 0) return;
+ if (_source) free(_source);
+ _source = NULL;
+ if (_target) free(_target);
+ _target = NULL;
+ _ecore_xcb_dnd_init_count = 0;
+}
+
+EAPI void
+ecore_x_dnd_send_status(Eina_Bool will_accept,
+ Eina_Bool suppress,
+ Ecore_X_Rectangle rect,
+ Ecore_X_Atom action)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ _target->will_accept = will_accept;
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.type = ECORE_X_ATOM_XDND_STATUS;
+ ev.format = 32;
+ ev.window = _target->source;
+ ev.data.data32[0] = _target->win;
+ ev.data.data32[1] = 0;
+ if (will_accept) ev.data.data32[1] |= 0x1UL;
+ if (!suppress) ev.data.data32[1] |= 0x2UL;
+
+ ev.data.data32[2] = rect.x;
+ ev.data.data32[2] <<= 16;
+ ev.data.data32[2] |= rect.y;
+ ev.data.data32[3] = rect.width;
+ ev.data.data32[3] <<= 16;
+ ev.data.data32[3] |= rect.height;
+
+ if (will_accept)
+ ev.data.data32[4] = action;
+ else
+ ev.data.data32[4] = XCB_NONE;
+ _target->accepted_action = action;
+
+ xcb_send_event(_ecore_xcb_conn, 0, _target->source,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_drop(void)
+{
+ xcb_client_message_event_t ev;
+ Eina_Bool status = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ if (_source->dest)
+ {
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = _source->dest;
+
+ if (_source->will_accept)
+ {
+ ev.type = ECORE_X_ATOM_XDND_DROP;
+ ev.data.data32[0] = _source->win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = _source->time;
+
+ xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _source->state = ECORE_X_DND_SOURCE_DROPPED;
+ status = EINA_TRUE;
+ }
+ else
+ {
+ ev.type = ECORE_X_ATOM_XDND_LEAVE;
+ ev.data.data32[0] = _source->win;
+ ev.data.data32[1] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+ }
+ else
+ {
+ ecore_x_selection_xdnd_clear();
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+
+ ecore_x_window_ignore_set(_source->win, 0);
+ _source->prev.window = 0;
+
+ return status;
+}
+
+EAPI void
+ecore_x_dnd_aware_set(Ecore_X_Window win,
+ Eina_Bool on)
+{
+ Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (on)
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE,
+ ECORE_X_ATOM_ATOM, 32, &prop_data, 1);
+ else
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE);
+}
+
+EAPI int
+ecore_x_dnd_version_get(Ecore_X_Window win)
+{
+ unsigned char *data;
+ int num = 0;
+ Version_Cache_Item *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ {
+ if (_version_cache)
+ {
+ int i = 0;
+
+ for (i = 0; i < _version_cache_num; i++)
+ {
+ if (_version_cache[i].win == win)
+ return _version_cache[i].ver;
+ }
+ }
+ }
+
+ if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE,
+ ECORE_X_ATOM_ATOM, 32, &data, &num))
+ {
+ int version = 0;
+
+ version = (int)*data;
+ free(data);
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ {
+ _version_cache_num++;
+ if (_version_cache_num > _version_cache_alloc)
+ _version_cache_alloc += 16;
+ t = realloc(_version_cache,
+ _version_cache_alloc * sizeof(Version_Cache_Item));
+ if (!t) return 0;
+ _version_cache = t;
+ _version_cache[_version_cache_num - 1].win = win;
+ _version_cache[_version_cache_num - 1].ver = version;
+ }
+ return version;
+ }
+
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ {
+ _version_cache_num++;
+ if (_version_cache_num > _version_cache_alloc)
+ _version_cache_alloc += 16;
+ t = realloc(_version_cache,
+ _version_cache_alloc * sizeof(Version_Cache_Item));
+ if (!t) return 0;
+ _version_cache = t;
+ _version_cache[_version_cache_num - 1].win = win;
+ _version_cache[_version_cache_num - 1].ver = 0;
+ }
+
+ return 0;
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_type_isset(Ecore_X_Window win,
+ const char *type)
+{
+ int num = 0, i = 0;
+ Eina_Bool ret = EINA_FALSE;
+ unsigned char *data;
+ Ecore_X_Atom *atoms, atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32, &data, &num))
+ return ret;
+
+ atom = ecore_x_atom_get(type);
+ atoms = (Ecore_X_Atom *)data;
+ for (i = 0; i < num; ++i)
+ {
+ if (atom == atoms[i])
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+ free(data);
+ return ret;
+}
+
+EAPI void
+ecore_x_dnd_type_set(Ecore_X_Window win,
+ const char *type,
+ Eina_Bool on)
+{
+ Ecore_X_Atom atom, *oldset = NULL, *newset = NULL;
+ int i = 0, j = 0, num = 0;
+ unsigned char *data = NULL, *old_data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ atom = ecore_x_atom_get(type);
+ ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32, &old_data, &num);
+ oldset = (Ecore_X_Atom *)old_data;
+ if (on)
+ {
+ if (ecore_x_dnd_type_isset(win, type))
+ {
+ free(old_data);
+ return;
+ }
+ newset = calloc(num + 1, sizeof(Ecore_X_Atom));
+ if (!newset) return;
+ data = (unsigned char *)newset;
+ for (i = 0; i < num; i++)
+ newset[i + 1] = oldset[i];
+ newset[0] = atom;
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32, data, num + 1);
+ }
+ else
+ {
+ if (!ecore_x_dnd_type_isset(win, type))
+ {
+ free(old_data);
+ return;
+ }
+ newset = calloc(num - 1, sizeof(Ecore_X_Atom));
+ if (!newset)
+ {
+ free(old_data);
+ return;
+ }
+ data = (unsigned char *)newset;
+ for (i = 0; i < num; i++)
+ if (oldset[i] != atom)
+ newset[j++] = oldset[i];
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32, data, num - 1);
+ }
+ free(oldset);
+ free(newset);
+}
+
+EAPI void
+ecore_x_dnd_types_set(Ecore_X_Window win,
+ const char **types,
+ unsigned int num_types)
+{
+ Ecore_X_Atom *newset = NULL;
+ unsigned int i;
+ unsigned char *data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!num_types)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST);
+ else
+ {
+ newset = calloc(num_types, sizeof(Ecore_X_Atom));
+ if (!newset) return;
+
+ data = (unsigned char *)newset;
+ for (i = 0; i < num_types; i++)
+ {
+ newset[i] = ecore_x_atom_get(types[i]);
+ ecore_x_selection_converter_atom_add(newset[i],
+ _ecore_xcb_dnd_converter_copy);
+ }
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32, data,
+ num_types);
+ free(newset);
+ }
+}
+
+EAPI void
+ecore_x_dnd_actions_set(Ecore_X_Window win,
+ Ecore_X_Atom *actions,
+ unsigned int num_actions)
+{
+ unsigned int i;
+ unsigned char *data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!num_actions)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST);
+ else
+ {
+ data = (unsigned char *)actions;
+ for (i = 0; i < num_actions; i++)
+ ecore_x_selection_converter_atom_add(actions[i],
+ _ecore_xcb_dnd_converter_copy);
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST,
+ ECORE_X_ATOM_ATOM, 32, data,
+ num_actions);
+ }
+}
+
+/**
+ * The DND position update cb is called Ecore_X sends a DND position to a
+ * client.
+ *
+ * It essentially mirrors some of the data sent in the position message.
+ * Generally this cb should be set just before position update is called.
+ * Please note well you need to look after your own data pointer if someone
+ * trashes you position update cb set.
+ *
+ * It is considered good form to clear this when the dnd event finishes.
+ *
+ * @param cb Callback to updated each time ecore_x sends a position update.
+ * @param data User data.
+ */
+EAPI void
+ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data),
+ const void *data)
+{
+ _posupdatecb = cb;
+ _posupdatedata = (void *)data;
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_begin(Ecore_X_Window source,
+ unsigned char *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_dnd_version_get(source)) return EINA_FALSE;
+
+ /* Take ownership of XdndSelection */
+ if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE;
+
+ if (_version_cache)
+ {
+ free(_version_cache);
+ _version_cache = NULL;
+ _version_cache_num = 0;
+ _version_cache_alloc = 0;
+ }
+
+ ecore_x_window_shadow_tree_flush();
+
+ _source->win = source;
+ ecore_x_window_ignore_set(_source->win, 1);
+ _source->state = ECORE_X_DND_SOURCE_DRAGGING;
+ _source->time = _ecore_xcb_events_last_time_get();
+ _source->prev.window = 0;
+
+ /* Default Accepted Action: move */
+ _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
+ _source->accepted_action = XCB_NONE;
+ _source->dest = XCB_NONE;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_dnd_send_finished(void)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (_target->state == ECORE_X_DND_TARGET_IDLE) return;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.type = ECORE_X_ATOM_XDND_FINISHED;
+ ev.window = _target->source;
+ ev.data.data32[0] = _target->win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ if (_target->will_accept)
+ {
+ ev.data.data32[1] |= 0x1UL;
+ ev.data.data32[2] = _target->accepted_action;
+ }
+
+ xcb_send_event(_ecore_xcb_conn, 0, _target->source,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _target->state = ECORE_X_DND_TARGET_IDLE;
+}
+
+EAPI void
+ecore_x_dnd_source_action_set(Ecore_X_Atom action)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _source->action = action;
+ if (_source->prev.window)
+ _ecore_xcb_dnd_drag(_source->prev.window,
+ _source->prev.x, _source->prev.y);
+}
+
+Ecore_X_DND_Source *
+_ecore_xcb_dnd_source_get(void)
+{
+ return _source;
+}
+
+Ecore_X_DND_Target *
+_ecore_xcb_dnd_target_get(void)
+{
+ return _target;
+}
+
+void
+_ecore_xcb_dnd_drag(Ecore_X_Window root,
+ int x,
+ int y)
+{
+ xcb_client_message_event_t ev;
+ Ecore_X_Window win, *skip;
+ Ecore_X_Xdnd_Position pos;
+ int num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+
+ skip = ecore_x_window_ignore_list(&num);
+ win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
+ while ((win) && !(ecore_x_dnd_version_get(win)))
+ win = ecore_x_window_shadow_parent_get(root, win);
+
+ if ((_source->dest) && (win != _source->dest))
+ {
+ ev.window = _source->dest;
+ ev.type = ECORE_X_ATOM_XDND_LEAVE;
+ ev.data.data32[0] = _source->win;
+ ev.data.data32[1] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, _source->dest,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _source->suppress = 0;
+ }
+
+ if (win)
+ {
+ int x1, x2, y1, y2;
+
+ _source->version = MIN(ECORE_X_DND_VERSION,
+ ecore_x_dnd_version_get(win));
+ if (win != _source->dest)
+ {
+ int i = 0;
+ unsigned char *data;
+ Ecore_X_Atom *types;
+
+ ecore_x_window_prop_property_get(_source->win,
+ ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32,
+ &data, &num);
+ types = (Ecore_X_Atom *)data;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_XDND_ENTER;
+ ev.data.data32[0] = _source->win;
+ ev.data.data32[1] = 0;
+ if (num > 3)
+ ev.data.data32[1] |= 0x1UL;
+ else
+ ev.data.data32[1] &= 0xfffffffeUL;
+ ev.data.data32[1] |= ((unsigned long)_source->version) << 24;
+
+ for (i = 2; i < 5; i++)
+ ev.data.data32[i] = 0;
+ for (i = 0; i < MIN(num, 3); ++i)
+ ev.data.data32[i + 2] = types[i];
+ free(data);
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _source->await_status = 0;
+ _source->will_accept = 0;
+ }
+
+ x1 = _source->rectangle.x;
+ x2 = _source->rectangle.x + _source->rectangle.width;
+ y1 = _source->rectangle.y;
+ y2 = _source->rectangle.y + _source->rectangle.height;
+
+ if ((!_source->await_status) || (!_source->suppress) ||
+ ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
+ {
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_XDND_POSITION;
+ ev.data.data32[0] = _source->win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
+ ev.data.data32[3] = _source->time;
+ ev.data.data32[4] = _source->action;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+ _source->await_status = 1;
+ }
+ }
+
+ if (_posupdatecb)
+ {
+ pos.position.x = x;
+ pos.position.y = y;
+ pos.win = win;
+ pos.prev = _source->dest;
+ _posupdatecb(_posupdatedata, &pos);
+ }
+
+ _source->prev.x = x;
+ _source->prev.y = y;
+ _source->prev.window = root;
+ _source->dest = win;
+}
+
+EAPI Ecore_X_Atom
+ecore_x_dnd_source_action_get(void)
+{
+ return _source->action;
+}
+
+/* local functions */
+static Eina_Bool
+_ecore_xcb_dnd_converter_copy(char *target EINA_UNUSED,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *tprop EINA_UNUSED,
+ int *count EINA_UNUSED)
+{
+ Ecore_Xcb_Textproperty text_prop;
+ Ecore_Xcb_Encoding_Style style = XcbTextStyle;
+ char *mystr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!data) || (!size)) return EINA_FALSE;
+
+ mystr = calloc(1, size + 1);
+ if (!mystr) return EINA_FALSE;
+
+ memcpy(mystr, data, size);
+ if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop))
+ {
+ int len;
+
+ len = strlen((char *)text_prop.value) + 1;
+ if (!(*data_ret = malloc(len)))
+ {
+ free(mystr);
+ return EINA_FALSE;
+ }
+ memcpy(*data_ret, text_prop.value, len);
+ *size_ret = len;
+ free(text_prop.value);
+ free(mystr);
+ return EINA_TRUE;
+ }
+ else
+ {
+ free(mystr);
+ return EINA_FALSE;
+ }
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_dpms.c b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c
new file mode 100644
index 0000000000..39ef589dd1
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c
@@ -0,0 +1,320 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_DAMAGE
+# include <xcb/dpms.h>
+#endif
+
+/* local variables */
+static Eina_Bool _dpms_avail = EINA_FALSE;
+
+void
+_ecore_xcb_dpms_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_DPMS
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_dpms_id);
+#endif
+}
+
+void
+_ecore_xcb_dpms_finalize(void)
+{
+#ifdef ECORE_XCB_DPMS
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_DPMS
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_dpms_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_dpms_get_version_cookie_t cookie;
+ xcb_dpms_get_version_reply_t *reply;
+
+ cookie =
+ xcb_dpms_get_version_unchecked(_ecore_xcb_conn,
+ XCB_DPMS_MAJOR_VERSION,
+ XCB_DPMS_MINOR_VERSION);
+ reply = xcb_dpms_get_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if (reply->server_major_version >= 1)
+ _dpms_avail = EINA_TRUE;
+ free(reply);
+ }
+ }
+#endif
+}
+
+/**
+ * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions
+ *
+ * Functions related to the X DPMS Extension
+ */
+
+/**
+ * Checks if the DPMS extension is available or not.
+ *
+ * @return @c EINA_TRUE if the DPMS extension is available,
+ * @c EINA_FALSE otherwise.
+ *
+ * Return @c EINA_TRUE if the X server supports the DPMS Extension version 1.0,
+ * @c EINA_FALSE otherwise.
+ *
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_query(void)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _dpms_avail;
+}
+
+/**
+ * Checks if the X server is capable of DPMS.
+ * @return @c 1 if the X server is capable of DPMS, @c 0 otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_capable_get(void)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_DPMS
+ xcb_dpms_capable_cookie_t cookie;
+ xcb_dpms_capable_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_dpms_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_DPMS
+ cookie = xcb_dpms_capable_unchecked(_ecore_xcb_conn);
+ reply = xcb_dpms_capable_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ ret = reply->capable;
+ free(reply);
+ }
+#endif
+
+ return ret;
+}
+
+/**
+ * Checks the DPMS state of the display.
+ * @return @c EINA_TRUE if DPMS is enabled, @c EINA_FALSE otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_enabled_get(void)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_DPMS
+ xcb_dpms_info_cookie_t cookie;
+ xcb_dpms_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_dpms_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_DPMS
+ cookie = xcb_dpms_info_unchecked(_ecore_xcb_conn);
+ reply = xcb_dpms_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+ if (reply->state) ret = EINA_TRUE;
+ free(reply);
+#endif
+
+ return ret;
+}
+
+/**
+ * Sets the DPMS state of the display.
+ * @param enabled @c 0 to disable DPMS characteristics of the server, enable it otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_enabled_set(int enabled)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_dpms_avail) return;
+
+#ifdef ECORE_XCB_DPMS
+ if (enabled)
+ xcb_dpms_enable(_ecore_xcb_conn);
+ else
+ xcb_dpms_disable(_ecore_xcb_conn);
+#endif
+}
+
+/**
+ * Gets the timeouts. The values are in unit of seconds.
+ * @param standby Amount of time of inactivity before standby mode will be invoked.
+ * @param suspend Amount of time of inactivity before the screen is placed into suspend mode.
+ * @param off Amount of time of inactivity before the monitor is shut off.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeouts_get(unsigned int *standby,
+ unsigned int *suspend,
+ unsigned int *off)
+{
+#ifdef ECORE_XCB_DPMS
+ xcb_dpms_get_timeouts_cookie_t cookie;
+ xcb_dpms_get_timeouts_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (standby) *standby = 0;
+ if (suspend) *suspend = 0;
+ if (off) *off = 0;
+
+ if (!_dpms_avail) return;
+
+#ifdef ECORE_XCB_DPMS
+ cookie = xcb_dpms_get_timeouts_unchecked(_ecore_xcb_conn);
+ reply = xcb_dpms_get_timeouts_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ if (standby) *standby = reply->standby_timeout;
+ if (suspend) *suspend = reply->suspend_timeout;
+ if (off) *off = reply->off_timeout;
+ free(reply);
+#endif
+}
+
+/**
+ * Sets the timeouts. The values are in unit of seconds.
+ *
+ * @param standby Amount of time of inactivity before standby mode will be invoked.
+ * @param suspend Amount of time of inactivity before the screen is placed into suspend mode.
+ * @param off Amount of time of inactivity before the monitor is shut off.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_timeouts_set(unsigned int standby,
+ unsigned int suspend,
+ unsigned int off)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_dpms_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_DPMS
+ // FIXME: Add request check
+ xcb_dpms_set_timeouts(_ecore_xcb_conn, standby, suspend, off);
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
+/**
+ * Returns the amount of time of inactivity before standby mode is invoked.
+ * @return The standby timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_standby_get(void)
+{
+ unsigned int standby = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(&standby, NULL, NULL);
+ return standby;
+}
+
+/**
+ * Returns the amount of time of inactivity before the second level of
+ * power saving is invoked.
+ * @return The suspend timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_suspend_get(void)
+{
+ unsigned int suspend = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(NULL, &suspend, NULL);
+ return suspend;
+}
+
+/**
+ * Returns the amount of time of inactivity before the third and final
+ * level of power saving is invoked.
+ * @return The off timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_off_get(void)
+{
+ unsigned int off = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(NULL, NULL, &off);
+ return off;
+}
+
+/**
+ * Sets the standby timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before standby mode will be invoked.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_standby_set(unsigned int new_timeout)
+{
+ unsigned int standby = 0, suspend = 0, off = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(&standby, &suspend, &off);
+ ecore_x_dpms_timeouts_set(new_timeout, suspend, off);
+}
+
+/**
+ * Sets the suspend timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before the screen is placed into suspend mode.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout)
+{
+ unsigned int standby = 0, suspend = 0, off = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(&standby, &suspend, &off);
+ ecore_x_dpms_timeouts_set(standby, new_timeout, off);
+}
+
+/**
+ * Sets the off timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before the monitor is shut off.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_off_set(unsigned int new_timeout)
+{
+ unsigned int standby = 0, suspend = 0, off = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_dpms_timeouts_get(&standby, &suspend, &off);
+ ecore_x_dpms_timeouts_set(standby, suspend, new_timeout);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_drawable.c b/src/lib/ecore_x/xcb/ecore_xcb_drawable.c
new file mode 100644
index 0000000000..4e9a3564ce
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_drawable.c
@@ -0,0 +1,123 @@
+#include "ecore_xcb_private.h"
+
+/**
+ * @defgroup Ecore_X_Drawable_Group X Drawable Functions
+ *
+ * Functions that operate on drawables.
+ */
+
+/**
+ * Fill the specified rectangle on a drawable.
+ * @param d The given drawable.
+ * @param gc The graphic context that controls the fill rules.
+ * @param x The X coordinate of the top-left corner of the rectangle.
+ * @param y The Y coordinate of the top-left corner of the rectangle.
+ * @param width The width of the rectangle.
+ * @param height The height of the rectangle.
+ */
+EAPI void
+ecore_x_drawable_rectangle_fill(Ecore_X_Drawable draw,
+ Ecore_X_GC gc,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ xcb_rectangle_t rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_poly_fill_rectangle(_ecore_xcb_conn, draw, gc, 1,
+ (const xcb_rectangle_t *)&rect);
+// ecore_x_flush();
+}
+
+/**
+ * Retrieves the geometry of the given drawable.
+ * @param d The given drawable.
+ * @param x Pointer to an integer into which the X position is to be stored.
+ * @param y Pointer to an integer into which the Y position is to be stored.
+ * @param w Pointer to an integer into which the width is to be stored.
+ * @param h Pointer to an integer into which the height is to be stored.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI void
+ecore_x_drawable_geometry_get(Ecore_X_Drawable draw,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = 0;
+ if (h) *h = 0;
+ cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, draw);
+ reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ if (x) *x = reply->x;
+ if (y) *y = reply->y;
+ if (w) *w = (int)reply->width;
+ if (h) *h = (int)reply->height;
+ free(reply);
+}
+
+/**
+ * Retrieves the width of the border of the given drawable.
+ * @param d The given drawable.
+ * @return The border width of the given drawable.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI int
+ecore_x_drawable_border_width_get(Ecore_X_Drawable d)
+{
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, d);
+ reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ ret = (int)reply->border_width;
+ free(reply);
+ return ret;
+}
+
+/**
+ * Retrieves the depth of the given drawable.
+ * @param d The given drawable.
+ * @return The depth of the given drawable.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI int
+ecore_x_drawable_depth_get(Ecore_X_Drawable d)
+{
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, d);
+ reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ ret = (int)reply->depth;
+ free(reply);
+ return ret;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_e.c b/src/lib/ecore_x/xcb/ecore_xcb_e.c
new file mode 100644
index 0000000000..82d94b634f
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_e.c
@@ -0,0 +1,1576 @@
+#include "ecore_xcb_private.h"
+
+/* local function prototypes */
+static Ecore_X_Atom _ecore_xcb_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state);
+static Ecore_X_Virtual_Keyboard_State _ecore_xcb_e_vkbd_state_get(Ecore_X_Atom atom);
+static Ecore_X_Atom _ecore_xcb_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state);
+static Ecore_X_Illume_Quickpanel_State _ecore_xcb_e_quickpanel_state_get(Ecore_X_Atom atom);
+static Ecore_X_Atom _ecore_xcb_e_illume_atom_get(Ecore_X_Illume_Mode mode);
+static Ecore_X_Illume_Mode _ecore_xcb_e_illume_mode_get(Ecore_X_Atom atom);
+static Ecore_X_Atom _ecore_xcb_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state);
+static Ecore_X_Illume_Indicator_State _ecore_xcb_e_indicator_state_get(Ecore_X_Atom atom);
+
+EAPI void
+ecore_x_e_init(void)
+{
+}
+
+EAPI void
+ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root,
+ Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root,
+ Ecore_X_Window win,
+ int w,
+ int h)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 1;
+ ev.data.data32[2] = w;
+ ev.data.data32[3] = h;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_sync_counter_set(Ecore_X_Window win,
+ Ecore_X_Sync_Counter counter)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (counter)
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER,
+ ECORE_X_ATOM_CARDINAL, &counter, 1);
+ else
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER);
+}
+
+EAPI Ecore_X_Sync_Counter
+ecore_x_e_comp_sync_counter_get(Ecore_X_Window win)
+{
+ Ecore_X_Sync_Counter counter = 0;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret = ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER,
+ ECORE_X_ATOM_CARDINAL, &counter, 1);
+ if (ret != 1) return 0;
+ return counter;
+}
+
+EAPI Eina_Bool
+ecore_x_e_comp_sync_supported_get(Ecore_X_Window root)
+{
+ Ecore_X_Window win, win2;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ ret =
+ ecore_x_window_prop_xid_get(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ if ((ret == 1) && (win))
+ {
+ ret =
+ ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win2, 1);
+ if ((ret == 1) && (win2 == win))
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_window_profile_list_set(Ecore_X_Window win,
+ const char **profiles,
+ unsigned int num_profiles)
+{
+ Ecore_X_Atom *atoms;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ return;
+
+ if (!num_profiles)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE_LIST);
+ else
+ {
+ atoms = alloca(num_profiles * sizeof(Ecore_X_Atom));
+ ecore_x_atoms_get(profiles, num_profiles, atoms);
+ ecore_x_window_prop_property_set(win,
+ ECORE_X_ATOM_E_PROFILE_LIST,
+ ECORE_X_ATOM_ATOM, 32, (void *)atoms,
+ num_profiles);
+ }
+}
+
+EAPI Eina_Bool
+ecore_x_e_window_profile_list_get(Ecore_X_Window win,
+ const char ***profiles,
+ int *ret_num)
+{
+ unsigned char *data = NULL;
+ Ecore_X_Atom *atoms;
+ int num, i;
+
+ if (ret_num)
+ *ret_num = 0;
+
+ if (profiles)
+ *profiles = NULL;
+
+ if (!win)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win,
+ ECORE_X_ATOM_E_PROFILE_LIST,
+ ECORE_X_ATOM_ATOM, 32, &data, &num))
+ return EINA_FALSE;
+
+ if (ret_num)
+ *ret_num = num;
+
+ if (profiles)
+ {
+ (*profiles) = calloc(num, sizeof(char *));
+ if (!(*profiles))
+ {
+ if (ret_num)
+ *ret_num = 0;
+
+ if (data)
+ free(data);
+
+ return EINA_FALSE;
+ }
+
+ atoms = (Ecore_X_Atom *)data;
+ for (i = 0; i < num; i++)
+ (*profiles)[i] = ecore_x_atom_name_get(atoms[i]);
+ }
+
+ if (data)
+ free(data);
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_window_profile_set(Ecore_X_Window win,
+ const char *profile)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ return;
+
+ if (!profile)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE);
+ else
+ {
+ atom = ecore_x_atom_get(profile);
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_E_PROFILE,
+ ECORE_X_ATOM_ATOM, 32, (void *)&atom, 1);
+ }
+}
+
+EAPI char *
+ecore_x_e_window_profile_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom *atom = NULL;
+ unsigned char *data;
+ char *profile = NULL;
+ int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_E_PROFILE,
+ ECORE_X_ATOM_ATOM, 32, &data, &num))
+ return NULL;
+
+ if (data)
+ atom = (Ecore_X_Atom *)data;
+
+ if (atom)
+ profile = ecore_x_atom_name_get(atom[0]);
+
+ return profile;
+}
+
+EAPI void
+ecore_x_e_comp_sync_supported_set(Ecore_X_Window root,
+ Eina_Bool enabled)
+{
+ Ecore_X_Window win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ if (enabled)
+ {
+ win = ecore_x_window_new(root, 1, 2, 3, 4);
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ ecore_x_window_prop_xid_set(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ }
+ else
+ {
+ int ret = 0;
+
+ ret = ecore_x_window_prop_xid_get(root,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ if ((ret == 1) && (win))
+ {
+ ecore_x_window_prop_property_del(root,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED);
+ ecore_x_window_free(win);
+ }
+ }
+}
+
+EAPI void
+ecore_x_e_comp_sync_begin_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_SYNC_BEGIN;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_sync_end_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_SYNC_END;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_SYNC_CANCEL;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_flush_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_FLUSH;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_dump_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_E_COMP_DUMP;
+ ev.data.data32[0] = win;
+ ev.data.data32[1] = 0;
+ ev.data.data32[2] = 0;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_e_comp_pixmap_set(Ecore_X_Window win,
+ Ecore_X_Pixmap pixmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (pixmap)
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_PIXMAP,
+ ECORE_X_ATOM_PIXMAP, &pixmap, 1);
+ else
+ ecore_x_window_prop_property_del(win, pixmap);
+}
+
+EAPI Ecore_X_Pixmap
+ecore_x_e_comp_pixmap_get(Ecore_X_Window win)
+{
+ Ecore_X_Pixmap pixmap = 0;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret = ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_PIXMAP,
+ ECORE_X_ATOM_PIXMAP, &pixmap, 1);
+ if (ret != 1) return 0;
+ return pixmap;
+}
+
+EAPI void
+ecore_x_e_frame_size_set(Ecore_X_Window win,
+ int fl,
+ int fr,
+ int ft,
+ int fb)
+{
+ uint32_t frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ frames[0] = fl;
+ frames[1] = fr;
+ frames[2] = ft;
+ frames[3] = fb;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_FRAME_SIZE, frames, 4);
+}
+
+EAPI Ecore_X_Virtual_Keyboard_State
+ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ &atom, 1))
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN;
+
+ return _ecore_xcb_e_vkbd_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win,
+ Ecore_X_Virtual_Keyboard_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ atom = _ecore_xcb_e_vkbd_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ &atom, 1);
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win,
+ Ecore_X_Virtual_Keyboard_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_xcb_e_vkbd_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_set(Ecore_X_Window win,
+ unsigned int is_keyboard)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD,
+ &is_keyboard, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_virtual_keyboard_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win,
+ unsigned int priority)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR,
+ &priority, 1);
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win,
+ unsigned int priority)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR,
+ &priority, 1);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win,
+ unsigned int zone)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE,
+ &zone, 1);
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_conformant_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_conformant_set(Ecore_X_Window win,
+ unsigned int is_conformant)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT,
+ &is_conformant, 1);
+}
+
+EAPI void
+ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ if (ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY,
+ geom, 4) != 4)
+ return EINA_FALSE;
+
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ if (ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY,
+ geom, 4) != 4)
+ return EINA_FALSE;
+
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ if (ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY,
+ geom, 4) != 4)
+ return EINA_FALSE;
+
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_set(Ecore_X_Window win,
+ unsigned int is_quickpanel)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL,
+ &is_quickpanel, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_quickpanel_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Quickpanel_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ atom = _ecore_xcb_e_quickpanel_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Quickpanel_State
+ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN;
+
+ return _ecore_xcb_e_quickpanel_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win,
+ Ecore_X_Illume_Quickpanel_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_xcb_e_quickpanel_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 0, 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_xcb_e_clipboard_atom_get(Ecore_X_Illume_Clipboard_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_CLIPBOARD_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON;
+ case ECORE_X_ILLUME_CLIPBOARD_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Clipboard_State
+_ecore_xcb_e_clipboard_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON)
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_ON;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF)
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_OFF;
+
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Clipboard_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_xcb_e_clipboard_atom_get(state);
+
+ ecore_x_window_prop_atom_set(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Clipboard_State
+ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN;
+ return _ecore_xcb_e_clipboard_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win,
+ int x, int y, int w, int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win,
+ int *x, int *y, int *w, int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY,
+ geom, 4);
+ if (ret != 4) return EINA_FALSE;
+
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_mode_set(Ecore_X_Window win,
+ Ecore_X_Illume_Mode mode)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ atom = _ecore_xcb_e_illume_atom_get(mode);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Mode
+ecore_x_e_illume_mode_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1))
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+
+ return _ecore_xcb_e_illume_mode_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_mode_send(Ecore_X_Window win,
+ Ecore_X_Illume_Mode mode)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_MODE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_xcb_e_illume_atom_get(mode),
+ 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_back_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_BACK,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_forward_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_home_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_HOME,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_close_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_CLOSE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_home_new_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_NEW,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_home_del_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_DEL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_next_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_up_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_down_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_drag_set(Ecore_X_Window win,
+ unsigned int drag)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG, &drag, 1);
+}
+
+EAPI void
+ecore_x_e_illume_drag_locked_set(Ecore_X_Window win,
+ unsigned int is_locked)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED,
+ &is_locked, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_drag_locked_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_drag_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG, &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_drag_start_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_START,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_drag_end_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_END,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_zone_set(Ecore_X_Window win,
+ Ecore_X_Window zone)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE, &zone, 1);
+}
+
+EAPI Ecore_X_Window
+ecore_x_e_illume_zone_get(Ecore_X_Window win)
+{
+ Ecore_X_Window zone;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_window_get(win, ECORE_X_ATOM_E_ILLUME_ZONE,
+ &zone, 1))
+ return 0;
+
+ return zone;
+}
+
+EAPI void
+ecore_x_e_illume_zone_list_set(Ecore_X_Window win,
+ Ecore_X_Window *zones,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE_LIST,
+ zones, num);
+}
+
+/* local functions */
+static Ecore_X_Atom
+_ecore_xcb_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_ON:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_IP:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_URL:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Virtual_Keyboard_State
+_ecore_xcb_e_vkbd_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_ON;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_IP;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_URL;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD;
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME;
+
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_QUICKPANEL_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON;
+
+ case ECORE_X_ILLUME_QUICKPANEL_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Quickpanel_State
+_ecore_xcb_e_quickpanel_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON)
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_ON;
+ if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF)
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_OFF;
+
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_e_illume_atom_get(Ecore_X_Illume_Mode mode)
+{
+ switch (mode)
+ {
+ case ECORE_X_ILLUME_MODE_SINGLE:
+ return ECORE_X_ATOM_E_ILLUME_MODE_SINGLE;
+
+ case ECORE_X_ILLUME_MODE_DUAL_TOP:
+ return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP;
+
+ case ECORE_X_ILLUME_MODE_DUAL_LEFT:
+ return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT;
+
+ default:
+ break;
+ }
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+}
+
+static Ecore_X_Illume_Mode
+_ecore_xcb_e_illume_mode_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_SINGLE)
+ return ECORE_X_ILLUME_MODE_SINGLE;
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP)
+ return ECORE_X_ILLUME_MODE_DUAL_TOP;
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT)
+ return ECORE_X_ILLUME_MODE_DUAL_LEFT;
+
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_INDICATOR_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_ON;
+
+ case ECORE_X_ILLUME_INDICATOR_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Indicator_State
+_ecore_xcb_e_indicator_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_ON)
+ return ECORE_X_ILLUME_INDICATOR_STATE_ON;
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF)
+ return ECORE_X_ILLUME_INDICATOR_STATE_OFF;
+
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_indicator_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ atom = _ecore_xcb_e_indicator_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Indicator_State
+ecore_x_e_illume_indicator_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+
+ return _ecore_xcb_e_indicator_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_indicator_state_send(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_xcb_e_indicator_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_indicator_opacity_atom_get(Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ switch (mode)
+ {
+ case ECORE_X_ILLUME_INDICATOR_OPAQUE:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE;
+
+ case ECORE_X_ILLUME_INDICATOR_TRANSLUCENT:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT;
+
+ case ECORE_X_ILLUME_INDICATOR_TRANSPARENT:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Indicator_Opacity_Mode
+_ecore_x_e_indicator_opacity_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE)
+ return ECORE_X_ILLUME_INDICATOR_OPAQUE;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT)
+ return ECORE_X_ILLUME_INDICATOR_TRANSLUCENT;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT)
+ return ECORE_X_ILLUME_INDICATOR_TRANSPARENT;
+
+ return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_indicator_opacity_atom_get(mode);
+ ecore_x_window_prop_atom_set(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Indicator_Opacity_Mode
+ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ &atom, 1))
+ return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN;
+
+ return _ecore_x_e_indicator_opacity_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_indicator_opacity_atom_get(mode),
+ 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_illume_window_state_atom_get(Ecore_X_Illume_Window_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_WINDOW_STATE_NORMAL:
+ return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL;
+
+ case ECORE_X_ILLUME_WINDOW_STATE_FLOATING:
+ return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Window_State
+_ecore_x_e_illume_window_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL)
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING)
+ return ECORE_X_ILLUME_WINDOW_STATE_FLOATING;
+
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+}
+
+EAPI void
+ecore_x_e_illume_window_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Window_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_illume_window_state_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_WINDOW_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Window_State
+ecore_x_e_illume_window_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_WINDOW_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+
+ return _ecore_x_e_illume_window_state_get(atom);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_error.c b/src/lib/ecore_x/xcb/ecore_xcb_error.c
new file mode 100644
index 0000000000..fc329265d5
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_error.c
@@ -0,0 +1,123 @@
+#include "ecore_xcb_private.h"
+#include <xcb/xcb_event.h>
+
+/* local variables */
+static void (*_error_func)(void *data) = NULL;
+static void *_error_data = NULL;
+static void (*_io_error_func)(void *data) = NULL;
+static void *_io_error_data = NULL;
+static int _error_request_code = 0;
+static int _error_code = 0;
+static Ecore_X_ID _error_resource_id = 0;
+
+/**
+ * Set the error handler.
+ * @param func The error handler function
+ * @param data The data to be passed to the handler function
+ *
+ * Set the X error handler function
+ */
+EAPI void
+ecore_x_error_handler_set(void (*func)(void *data),
+ const void *data)
+{
+ _error_func = func;
+ _error_data = (void *)data;
+}
+
+/**
+ * Set the I/O error handler.
+ * @param func The I/O error handler function
+ * @param data The data to be passed to the handler function
+ *
+ * Set the X I/O error handler function
+ */
+EAPI void
+ecore_x_io_error_handler_set(void (*func)(void *data),
+ const void *data)
+{
+ _io_error_func = func;
+ _io_error_data = (void *)data;
+}
+
+/**
+ * Get the request code that caused the error.
+ * @return The request code causing the X error
+ *
+ * Return the X request code that caused the last X error
+ */
+EAPI int
+ecore_x_error_request_get(void)
+{
+ return _error_request_code;
+}
+
+/**
+ * Get the error code from the error.
+ * @return The error code from the X error
+ *
+ * Return the error code from the last X error
+ */
+EAPI int
+ecore_x_error_code_get(void)
+{
+ return _error_code;
+}
+
+/**
+ * Get the resource id that caused the error.
+ * @return The resource id causing the X error
+ *
+ * Return the X resource id that caused the last X error
+ */
+EAPI Ecore_X_ID
+ecore_x_error_resource_id_get(void)
+{
+ return _error_resource_id;
+}
+
+int
+_ecore_xcb_error_handle(xcb_generic_error_t *err)
+{
+ WRN("Got Error:");
+ WRN("\tEvent: %s", xcb_event_get_request_label(err->major_code));
+ WRN("\tError: %s", xcb_event_get_error_label(err->error_code));
+
+#ifdef OLD_XCB_VERSION
+ if (err->error_code == XCB_EVENT_ERROR_BAD_VALUE)
+ WRN("\tBad Value: %d", ((xcb_value_error_t *)err)->bad_value);
+ else if (err->error_code == XCB_EVENT_ERROR_BAD_WINDOW)
+ WRN("\tBad Window: %d", ((xcb_window_error_t *)err)->bad_value);
+#else
+ if (err->error_code == XCB_VALUE)
+ WRN("\tBad Value: %d", ((xcb_value_error_t *)err)->bad_value);
+ else if (err->error_code == XCB_WINDOW)
+ WRN("\tBad Window: %d", ((xcb_window_error_t *)err)->bad_value);
+#endif
+
+ _error_request_code = err->sequence;
+ _error_code = err->error_code;
+ _error_resource_id = err->resource_id;
+ if (_error_func)
+ _error_func(_error_data);
+
+ return 0;
+}
+
+int
+_ecore_xcb_io_error_handle(xcb_generic_error_t *err)
+{
+ CRIT("IO Error:");
+ if (err)
+ {
+ CRIT("\tRequest: %d", err->sequence);
+ CRIT("\tCode: %d", err->error_code);
+ }
+ if (_io_error_func)
+ _io_error_func(_io_error_data);
+ else
+ exit(-1);
+
+ return 0;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_events.c b/src/lib/ecore_x/xcb/ecore_xcb_events.c
new file mode 100644
index 0000000000..9cc86f62a8
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_events.c
@@ -0,0 +1,2824 @@
+#include "ecore_xcb_private.h"
+//#include "Ecore_X_Atoms.h"
+#include <langinfo.h>
+#include <xcb/xcb_icccm.h>
+#include <xcb/xcb_event.h>
+# ifdef ECORE_XCB_DAMAGE
+# include <xcb/damage.h>
+# endif
+# ifdef ECORE_XCB_RANDR
+# include <xcb/randr.h>
+# endif
+# ifdef ECORE_XCB_SCREENSAVER
+# include <xcb/screensaver.h>
+# endif
+# ifdef ECORE_XCB_SYNC
+# include <xcb/sync.h>
+# endif
+# ifdef ECORE_XCB_XFIXES
+# include <xcb/xfixes.h>
+# endif
+# ifdef ECORE_XCB_XGESTURE
+# include <xcb/gesture.h>
+# endif
+
+#ifndef CODESET
+# define CODESET "INVALID"
+#endif
+
+typedef struct _Ecore_X_Mouse_Down_Info
+{
+ EINA_INLIST;
+ int dev;
+ Ecore_X_Time last_time;
+ Ecore_X_Time last_last_time;
+ Ecore_X_Window last_win;
+ Ecore_X_Window last_last_win;
+ Ecore_X_Window last_event_win;
+ Ecore_X_Window last_last_event_win;
+ Eina_Bool did_double : 1;
+ Eina_Bool did_triple : 1;
+} Ecore_X_Mouse_Down_Info;
+
+/* local function prototypes */
+static void _ecore_xcb_event_handle_any_event(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_key_press(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_key_release(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_button_press(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_button_release(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_motion_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_enter_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_leave_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_keymap_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_focus_in(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_focus_out(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_expose(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_graphics_exposure(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_visibility_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_create_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_destroy_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_map_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_unmap_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_map_request(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_reparent_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_configure_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_configure_request(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gravity_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_resize_request(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_circulate_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_circulate_request(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_property_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_selection_clear(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_selection_request(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_selection_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_colormap_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_client_message(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_mapping_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_damage_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_randr_change(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_randr_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_randr_crtc_change(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_randr_output_change(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_randr_output_property_change(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_screensaver_notify(xcb_generic_event_t *event);
+#ifdef ECORE_XCB_XGESTURE
+static void _ecore_xcb_event_handle_gesture_notify_flick(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_pan(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_pinchrotation(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_tap(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_tapnhold(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_hold(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_gesture_notify_group(xcb_generic_event_t *event);
+#endif
+#ifdef ECORE_XCB_SHAPE
+static void _ecore_xcb_event_handle_shape_change(xcb_generic_event_t *event);
+#endif
+static void _ecore_xcb_event_handle_sync_counter(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_sync_alarm(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_xfixes_selection_notify(xcb_generic_event_t *event EINA_UNUSED);
+static void _ecore_xcb_event_handle_xfixes_cursor_notify(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_generic_event(xcb_generic_event_t *event);
+static void _ecore_xcb_event_handle_input_event(xcb_generic_event_t *event);
+
+static void _ecore_xcb_event_key_press(xcb_generic_event_t *event);
+static void _ecore_xcb_event_key_release(xcb_generic_event_t *event);
+static void _ecore_xcb_event_mouse_move_free(void *data EINA_UNUSED,
+ void *event);
+static Ecore_X_Event_Mode _ecore_xcb_event_mode_get(uint8_t mode);
+static Ecore_X_Event_Detail _ecore_xcb_event_detail_get(uint8_t detail);
+static void _ecore_xcb_event_xdnd_enter_free(void *data EINA_UNUSED,
+ void *event);
+static void _ecore_xcb_event_selection_notify_free(void *data EINA_UNUSED,
+ void *event);
+static void _ecore_xcb_event_generic_event_free(void *data,
+ void *event);
+static void _ecore_xcb_event_mouse_down_info_clear(void);
+static Ecore_X_Mouse_Down_Info *_ecore_xcb_event_mouse_down_info_get(int dev);
+
+/* local variables */
+static Eina_Bool _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+//static Ecore_Event *_ecore_xcb_event_last_mouse_move_event = NULL;
+static Eina_Inlist *_ecore_xcb_mouse_down_info_list = NULL;
+static Ecore_X_Time _ecore_xcb_event_last_time;
+static Ecore_X_Window _ecore_xcb_event_last_window = 0;
+
+/* public variables */
+int16_t _ecore_xcb_event_last_root_x = 0;
+int16_t _ecore_xcb_event_last_root_y = 0;
+
+EAPI int ECORE_X_EVENT_ANY = 0;
+EAPI int ECORE_X_EVENT_MOUSE_IN = 0;
+EAPI int ECORE_X_EVENT_MOUSE_OUT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_FOCUS_IN = 0;
+EAPI int ECORE_X_EVENT_WINDOW_FOCUS_OUT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_KEYMAP = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DAMAGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CREATE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DESTROY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_HIDE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHOW = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHOW_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_REPARENT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_GRAVITY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STACK = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STACK_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_PROPERTY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_COLORMAP = 0;
+EAPI int ECORE_X_EVENT_WINDOW_MAPPING = 0;
+EAPI int ECORE_X_EVENT_MAPPING_CHANGE = 0;
+EAPI int ECORE_X_EVENT_SELECTION_CLEAR = 0;
+EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0;
+EAPI int ECORE_X_EVENT_SELECTION_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_CLIENT_MESSAGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHAPE = 0;
+EAPI int ECORE_X_EVENT_SCREENSAVER_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PAN = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAP = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = 0;
+EAPI int ECORE_X_EVENT_SYNC_COUNTER = 0;
+EAPI int ECORE_X_EVENT_SYNC_ALARM = 0;
+EAPI int ECORE_X_EVENT_SCREEN_CHANGE = 0;
+EAPI int ECORE_X_EVENT_DAMAGE_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_RANDR_CRTC_CHANGE = 0;
+EAPI int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = 0;
+EAPI int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DELETE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STATE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = 0;
+EAPI int ECORE_X_EVENT_PING = 0;
+EAPI int ECORE_X_EVENT_DESKTOP_CHANGE = 0;
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = 0;
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = 0;
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = 0;
+EAPI int ECORE_X_EVENT_XKB_STATE_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_GENERIC = 0;
+
+EAPI int ECORE_X_RAW_BUTTON_PRESS = 0;
+EAPI int ECORE_X_RAW_BUTTON_RELEASE = 0;
+EAPI int ECORE_X_RAW_MOTION = 0;
+
+void
+_ecore_xcb_events_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ECORE_X_EVENT_ANY)
+ {
+ ECORE_X_EVENT_ANY = ecore_event_type_new();
+ ECORE_X_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_X_EVENT_MOUSE_OUT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_KEYMAP = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_DAMAGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CREATE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_DESTROY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_HIDE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHOW = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHOW_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_REPARENT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_GRAVITY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STACK = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STACK_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_PROPERTY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_COLORMAP = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_MAPPING = ecore_event_type_new();
+ ECORE_X_EVENT_MAPPING_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_CLEAR = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_CLIENT_MESSAGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHAPE = ecore_event_type_new();
+ ECORE_X_EVENT_SCREENSAVER_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_PAN = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_TAP = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = ecore_event_type_new();
+ ECORE_X_EVENT_SYNC_COUNTER = ecore_event_type_new();
+ ECORE_X_EVENT_SYNC_ALARM = ecore_event_type_new();
+ ECORE_X_EVENT_SCREEN_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_CRTC_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_DAMAGE_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_DESKTOP_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STATE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_PING = ecore_event_type_new();
+ ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = ecore_event_type_new();
+ ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = ecore_event_type_new();
+ ECORE_X_EVENT_XKB_STATE_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_GENERIC = ecore_event_type_new();
+
+ ECORE_X_RAW_BUTTON_PRESS = ecore_event_type_new();
+ ECORE_X_RAW_BUTTON_RELEASE = ecore_event_type_new();
+ ECORE_X_RAW_MOTION = ecore_event_type_new();
+ }
+}
+
+void
+_ecore_xcb_events_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_event_mouse_down_info_clear();
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+// if (_ecore_xcb_event_last_mouse_move_event)
+// {
+// ecore_event_del(_ecore_xcb_event_last_mouse_move_event);
+// _ecore_xcb_event_last_mouse_move_event = NULL;
+// }
+}
+
+void
+_ecore_xcb_events_handle(xcb_generic_event_t *ev)
+{
+ uint8_t response = 0;
+
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ /* strip highest bit (set if event is generated) */
+ response = (ev->response_type & ~0x80);
+ if (response == 0)
+ {
+ xcb_generic_error_t *err;
+
+ err = (xcb_generic_error_t *)ev;
+
+ /* NB: There is no way to check access of destroyed windows,
+ * so trap those cases and ignore. We also ignore BadValue from
+ * xcb_grab/ungrab_button (happens when we are using any_mod)
+ * and a few others */
+#ifdef OLD_XCB_VERSION
+ if (err->error_code == XCB_EVENT_ERROR_BAD_WINDOW) return;
+ else if (err->error_code == XCB_EVENT_ERROR_BAD_MATCH)
+ {
+ if ((err->major_code == XCB_SET_INPUT_FOCUS) ||
+ (err->major_code == XCB_CONFIGURE_WINDOW))
+ return;
+ }
+ else if (err->error_code == XCB_EVENT_ERROR_BAD_VALUE)
+ {
+ if ((err->major_code == XCB_KILL_CLIENT) ||
+ (err->major_code == XCB_GRAB_BUTTON) ||
+ (err->major_code == XCB_UNGRAB_BUTTON))
+ return;
+ }
+#else
+ if (err->error_code == XCB_WINDOW) return;
+ else if (err->error_code == XCB_MATCH)
+ {
+ if ((err->major_code == XCB_SET_INPUT_FOCUS) ||
+ (err->major_code == XCB_CONFIGURE_WINDOW))
+ return;
+ }
+ else if (err->error_code == XCB_VALUE)
+ {
+ if ((err->major_code == XCB_KILL_CLIENT) ||
+ (err->major_code == XCB_GRAB_BUTTON) ||
+ (err->major_code == XCB_UNGRAB_BUTTON))
+ return;
+ }
+#endif
+ WRN("Got Event Error:");
+ WRN("\tMajor Code: %d", err->major_code);
+ WRN("\tMinor Code: %d", err->minor_code);
+ WRN("\tRequest: %s", xcb_event_get_request_label(err->major_code));
+ WRN("\tError: %s", xcb_event_get_error_label(err->error_code));
+ if (err->error_code == 2) // bad value
+ WRN("\tValue: %d", ((xcb_value_error_t *)err)->bad_value);
+ else if (err->error_code == 8) // bad match
+ WRN("\tMatch: %d", ((xcb_match_error_t *)err)->bad_value);
+
+ if (err->major_code == XCB_SEND_EVENT)
+ {
+ WRN("\tSend Event Error");
+ WRN("\t\tSeq: %d", ev->sequence);
+ WRN("\t\tFull Seq: %d", ev->full_sequence);
+ WRN("\t\tType: %d", ev->response_type);
+ }
+ /* if (err->major_code == 148) */
+ /* { */
+ /* printf("GOT 148 Error\n"); */
+ /* } */
+ return;
+ }
+
+ /* FIXME: Filter event for xim when xcb supports xim */
+
+ _ecore_xcb_event_handle_any_event(ev);
+
+ if (response == XCB_KEY_PRESS)
+ _ecore_xcb_event_handle_key_press(ev);
+ else if (response == XCB_KEY_RELEASE)
+ _ecore_xcb_event_handle_key_release(ev);
+ else if (response == XCB_BUTTON_PRESS)
+ _ecore_xcb_event_handle_button_press(ev);
+ else if (response == XCB_BUTTON_RELEASE)
+ _ecore_xcb_event_handle_button_release(ev);
+ else if (response == XCB_MOTION_NOTIFY)
+ _ecore_xcb_event_handle_motion_notify(ev);
+ else if (response == XCB_ENTER_NOTIFY)
+ _ecore_xcb_event_handle_enter_notify(ev);
+ else if (response == XCB_LEAVE_NOTIFY)
+ _ecore_xcb_event_handle_leave_notify(ev);
+ else if (response == XCB_KEYMAP_NOTIFY)
+ _ecore_xcb_event_handle_keymap_notify(ev);
+ else if (response == XCB_FOCUS_IN)
+ _ecore_xcb_event_handle_focus_in(ev);
+ else if (response == XCB_FOCUS_OUT)
+ _ecore_xcb_event_handle_focus_out(ev);
+ else if (response == XCB_EXPOSE)
+ _ecore_xcb_event_handle_expose(ev);
+ else if (response == XCB_GRAPHICS_EXPOSURE)
+ _ecore_xcb_event_handle_graphics_exposure(ev);
+ else if (response == XCB_VISIBILITY_NOTIFY)
+ _ecore_xcb_event_handle_visibility_notify(ev);
+ else if (response == XCB_CREATE_NOTIFY)
+ _ecore_xcb_event_handle_create_notify(ev);
+ else if (response == XCB_DESTROY_NOTIFY)
+ _ecore_xcb_event_handle_destroy_notify(ev);
+ else if (response == XCB_MAP_NOTIFY)
+ _ecore_xcb_event_handle_map_notify(ev);
+ else if (response == XCB_UNMAP_NOTIFY)
+ _ecore_xcb_event_handle_unmap_notify(ev);
+ else if (response == XCB_MAP_REQUEST)
+ _ecore_xcb_event_handle_map_request(ev);
+ else if (response == XCB_REPARENT_NOTIFY)
+ _ecore_xcb_event_handle_reparent_notify(ev);
+ else if (response == XCB_CONFIGURE_NOTIFY)
+ _ecore_xcb_event_handle_configure_notify(ev);
+ else if (response == XCB_CONFIGURE_REQUEST)
+ _ecore_xcb_event_handle_configure_request(ev);
+ else if (response == XCB_GRAVITY_NOTIFY)
+ _ecore_xcb_event_handle_gravity_notify(ev);
+ else if (response == XCB_RESIZE_REQUEST)
+ _ecore_xcb_event_handle_resize_request(ev);
+ else if (response == XCB_CIRCULATE_NOTIFY)
+ _ecore_xcb_event_handle_circulate_notify(ev);
+ else if (response == XCB_CIRCULATE_REQUEST)
+ _ecore_xcb_event_handle_circulate_request(ev);
+ else if (response == XCB_PROPERTY_NOTIFY)
+ _ecore_xcb_event_handle_property_notify(ev);
+ else if (response == XCB_SELECTION_CLEAR)
+ _ecore_xcb_event_handle_selection_clear(ev);
+ else if (response == XCB_SELECTION_REQUEST)
+ _ecore_xcb_event_handle_selection_request(ev);
+ else if (response == XCB_SELECTION_NOTIFY)
+ _ecore_xcb_event_handle_selection_notify(ev);
+ else if (response == XCB_COLORMAP_NOTIFY)
+ _ecore_xcb_event_handle_colormap_notify(ev);
+ else if (response == XCB_CLIENT_MESSAGE)
+ _ecore_xcb_event_handle_client_message(ev);
+ else if (response == XCB_MAPPING_NOTIFY)
+ _ecore_xcb_event_handle_mapping_notify(ev);
+ else if (response == 35) /* GenericEvent == 35 */
+ _ecore_xcb_event_handle_generic_event(ev);
+#ifdef ECORE_XCB_DAMAGE
+ else if ((_ecore_xcb_event_damage >= 0) &&
+ (response == (_ecore_xcb_event_damage + XCB_DAMAGE_NOTIFY)))
+ _ecore_xcb_event_handle_damage_notify(ev);
+#endif
+#ifdef ECORE_XCB_RANDR
+ else if ((_ecore_xcb_event_randr >= 0) &&
+ (response ==
+ _ecore_xcb_event_randr + XCB_RANDR_SCREEN_CHANGE_NOTIFY))
+ _ecore_xcb_event_handle_randr_change(ev);
+ else if ((_ecore_xcb_event_randr >= 0) &&
+ (response == (_ecore_xcb_event_randr + XCB_RANDR_NOTIFY)))
+ _ecore_xcb_event_handle_randr_notify(ev);
+#endif
+#ifdef ECORE_XCB_SCREENSAVER
+ else if ((_ecore_xcb_event_screensaver >= 0) &&
+ (response ==
+ _ecore_xcb_event_screensaver + XCB_SCREENSAVER_NOTIFY))
+ _ecore_xcb_event_handle_screensaver_notify(ev);
+#endif
+#ifdef ECORE_XCB_XGESTURE
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_FLICK))
+ _ecore_xcb_event_handle_gesture_notify_flick(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_PAN))
+ _ecore_xcb_event_handle_gesture_notify_pan(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_PINCH_ROTATION))
+ _ecore_xcb_event_handle_gesture_notify_pinchrotation(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_TAP))
+ _ecore_xcb_event_handle_gesture_notify_tap(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_TAP_N_HOLD))
+ _ecore_xcb_event_handle_gesture_notify_tapnhold(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_HOLD))
+ _ecore_xcb_event_handle_gesture_notify_hold(ev);
+ else if ((_ecore_xcb_event_gesture >= 0) &&
+ (response ==
+ _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_GROUP))
+ _ecore_xcb_event_handle_gesture_notify_group(ev);
+#endif
+#ifdef ECORE_XCB_SHAPE
+ else if ((_ecore_xcb_event_shape >= 0) &&
+ (response == (_ecore_xcb_event_shape + XCB_SHAPE_NOTIFY)))
+ _ecore_xcb_event_handle_shape_change(ev);
+#endif
+#ifdef ECORE_XCB_SYNC
+ else if ((_ecore_xcb_event_sync >= 0) &&
+ (response == (_ecore_xcb_event_sync + XCB_SYNC_COUNTER_NOTIFY)))
+ _ecore_xcb_event_handle_sync_counter(ev);
+ else if ((_ecore_xcb_event_sync >= 0) &&
+ (response == (_ecore_xcb_event_sync + XCB_SYNC_ALARM_NOTIFY)))
+ _ecore_xcb_event_handle_sync_alarm(ev);
+#endif
+#ifdef ECORE_XCB_XFIXES
+ else if ((_ecore_xcb_event_xfixes >= 0) &&
+ (response ==
+ _ecore_xcb_event_xfixes + XCB_XFIXES_SELECTION_NOTIFY))
+ _ecore_xcb_event_handle_xfixes_selection_notify(ev);
+ else if ((_ecore_xcb_event_xfixes >= 0) &&
+ (response == (_ecore_xcb_event_xfixes + XCB_XFIXES_CURSOR_NOTIFY)))
+ _ecore_xcb_event_handle_xfixes_cursor_notify(ev);
+#endif
+}
+
+Ecore_X_Time
+_ecore_xcb_events_last_time_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_event_last_time;
+}
+
+EAPI void
+ecore_x_event_mask_set(Ecore_X_Window win,
+ Ecore_X_Event_Mask mask)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+
+ list = (mask | reply->your_event_mask);
+ free(reply);
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_event_mask_unset(Ecore_X_Window win,
+ Ecore_X_Event_Mask mask)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+
+ list = (reply->your_event_mask & ~mask);
+ free(reply);
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+// ecore_x_flush();
+}
+
+unsigned int
+_ecore_xcb_events_modifiers_get(unsigned int state)
+{
+ unsigned int modifiers = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (state & ECORE_X_MODIFIER_SHIFT)
+ modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+ if (state & ECORE_X_MODIFIER_CTRL)
+ modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+ if (state & ECORE_X_MODIFIER_ALT)
+ modifiers |= ECORE_EVENT_MODIFIER_ALT;
+ if (state & ECORE_X_MODIFIER_WIN)
+ modifiers |= ECORE_EVENT_MODIFIER_WIN;
+ if (state & ECORE_X_MODIFIER_ALTGR)
+ modifiers |= ECORE_EVENT_MODIFIER_ALTGR;
+ if (state & ECORE_X_LOCK_SCROLL)
+ modifiers |= ECORE_EVENT_LOCK_SCROLL;
+ if (state & ECORE_X_LOCK_CAPS)
+ modifiers |= ECORE_EVENT_LOCK_CAPS;
+ if (state & ECORE_X_LOCK_NUM)
+ modifiers |= ECORE_EVENT_LOCK_NUM;
+ if (state & ECORE_X_LOCK_SHIFT)
+ modifiers |= ECORE_EVENT_LOCK_SHIFT;
+
+ return modifiers;
+}
+
+/* local functions */
+static void
+_ecore_xcb_event_handle_any_event(xcb_generic_event_t *event)
+{
+ xcb_generic_event_t *ev;
+
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ev = malloc(sizeof(xcb_generic_event_t));
+ if (!ev) return;
+
+ memcpy(ev, event, sizeof(xcb_generic_event_t));
+ ecore_event_add(ECORE_X_EVENT_ANY, ev, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_key_press(xcb_generic_event_t *event)
+{
+ _ecore_xcb_event_key_press(event);
+}
+
+static void
+_ecore_xcb_event_handle_key_release(xcb_generic_event_t *event)
+{
+ _ecore_xcb_event_key_release(event);
+}
+
+static void
+_ecore_xcb_event_handle_button_press(xcb_generic_event_t *event)
+{
+ xcb_button_press_event_t *ev;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+
+ ev = (xcb_button_press_event_t *)event;
+ if ((ev->detail > 3) && (ev->detail < 8))
+ {
+ Ecore_Event_Mouse_Wheel *e;
+
+ if (!(e = malloc(sizeof(Ecore_Event_Mouse_Wheel)))) return;
+
+ e->timestamp = ev->time;
+ e->modifiers = _ecore_xcb_events_modifiers_get(ev->state);
+ switch (ev->detail)
+ {
+ case 4:
+ e->direction = 0;
+ e->z = -1;
+ break;
+
+ case 5:
+ e->direction = 0;
+ e->z = 1;
+ break;
+
+ case 6:
+ e->direction = 1;
+ e->z = -1;
+ break;
+
+ case 7:
+ e->direction = 1;
+ e->z = 1;
+ break;
+
+ default:
+ e->direction = 0;
+ e->z = 0;
+ break;
+ }
+ e->x = ev->event_x;
+ e->y = ev->event_y;
+ e->root.x = ev->root_x;
+ e->root.y = ev->root_y;
+ if (ev->child)
+ e->window = ev->child;
+ else
+ e->window = ev->event;
+
+ e->event_window = ev->event;
+ e->same_screen = ev->same_screen;
+ e->root_window = ev->root;
+
+ _ecore_xcb_event_last_time = e->timestamp;
+ _ecore_xcb_event_last_window = e->window;
+ _ecore_xcb_event_last_root_x = e->root.x;
+ _ecore_xcb_event_last_root_y = e->root.y;
+
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL);
+
+ _ecore_xcb_window_grab_allow_events(ev->event, ev->child,
+ ECORE_EVENT_MOUSE_WHEEL,
+ e, ev->time);
+ }
+ else
+ {
+ Ecore_Event_Mouse_Button *e;
+ unsigned int child_win = 0;
+
+ child_win = (ev->child ? ev->child : ev->event);
+
+ _ecore_xcb_event_mouse_move(ev->time, ev->state,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y,
+ ev->event, child_win,
+ ev->root, ev->same_screen,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+
+ e = _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ ev->time,
+ ev->state, ev->detail,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y, ev->event,
+ child_win,
+ ev->root, ev->same_screen,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+ if (e)
+ _ecore_xcb_window_grab_allow_events(ev->event, ev->child,
+ ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ e, ev->time);
+ }
+}
+
+static void
+_ecore_xcb_event_handle_button_release(xcb_generic_event_t *event)
+{
+ xcb_button_release_event_t *ev;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_button_release_event_t *)event;
+ if ((ev->detail <= 3) || (ev->detail > 7))
+ {
+ _ecore_xcb_event_mouse_move(ev->time, ev->state,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y,
+ ev->event,
+ (ev->child ? ev->child : ev->event),
+ ev->root, ev->same_screen,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+
+ _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP, ev->time,
+ ev->state, ev->detail,
+ ev->event_x, ev->event_y, ev->root_x,
+ ev->root_y, ev->event,
+ (ev->child ? ev->child : ev->event),
+ ev->root, ev->same_screen,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+ }
+}
+
+static void
+_ecore_xcb_event_handle_motion_notify(xcb_generic_event_t *event)
+{
+ xcb_motion_notify_event_t *ev;
+
+ ev = (xcb_motion_notify_event_t *)event;
+
+ /* if (_ecore_xcb_event_last_mouse_move_event) */
+ /* { */
+ /* ecore_event_del(_ecore_xcb_event_last_mouse_move_event); */
+ /* _ecore_xcb_event_last_mouse_move = EINA_FALSE; */
+ /* _ecore_xcb_event_last_mouse_move_event = NULL; */
+ /* } */
+
+ _ecore_xcb_event_mouse_move(ev->time, ev->state,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y,
+ ev->event,
+ (ev->child ? ev->child : ev->event),
+ ev->root, ev->same_screen,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+ _ecore_xcb_event_last_mouse_move = EINA_TRUE;
+
+ _ecore_xcb_dnd_drag(ev->root, ev->root_x, ev->root_y);
+}
+
+static void
+_ecore_xcb_event_handle_enter_notify(xcb_generic_event_t *event)
+{
+ xcb_enter_notify_event_t *ev;
+ Ecore_X_Event_Mouse_In *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_enter_notify_event_t *)event;
+
+ _ecore_xcb_event_mouse_move(ev->time, ev->state,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y,
+ ev->event,
+ (ev->child ? ev->child : ev->event),
+ ev->root, ev->same_screen_focus,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Mouse_In)))) return;
+
+ e->modifiers = _ecore_xcb_events_modifiers_get(ev->state);
+ e->x = ev->event_x;
+ e->y = ev->event_y;
+ e->root.x = ev->root_x;
+ e->root.y = ev->root_y;
+ if (ev->child)
+ e->win = ev->child;
+ else
+ e->win = ev->event;
+ e->event_win = ev->event;
+ e->same_screen = ev->same_screen_focus;
+ e->root_win = ev->root;
+ e->mode = _ecore_xcb_event_mode_get(ev->mode);
+ e->detail = _ecore_xcb_event_detail_get(ev->detail);
+ e->time = ev->time;
+ _ecore_xcb_event_last_time = e->time;
+
+ ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_leave_notify(xcb_generic_event_t *event)
+{
+ xcb_leave_notify_event_t *ev;
+ Ecore_X_Event_Mouse_Out *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_enter_notify_event_t *)event;
+
+ _ecore_xcb_event_mouse_move(ev->time, ev->state,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y,
+ ev->event,
+ (ev->child ? ev->child : ev->event),
+ ev->root, ev->same_screen_focus,
+ 0, 1, 1, 1.0, 0.0,
+ ev->event_x, ev->event_y,
+ ev->root_x, ev->root_y);
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out)))) return;
+
+ e->modifiers = _ecore_xcb_events_modifiers_get(ev->state);
+ e->x = ev->event_x;
+ e->y = ev->event_y;
+ e->root.x = ev->root_x;
+ e->root.y = ev->root_y;
+ if (ev->child)
+ e->win = ev->child;
+ else
+ e->win = ev->event;
+ e->event_win = ev->event;
+ e->same_screen = ev->same_screen_focus;
+ e->root_win = ev->root;
+ e->mode = _ecore_xcb_event_mode_get(ev->mode);
+ e->detail = _ecore_xcb_event_detail_get(ev->detail);
+
+ e->time = ev->time;
+ _ecore_xcb_event_last_time = e->time;
+ _ecore_xcb_event_last_window = e->win;
+ _ecore_xcb_event_last_root_x = e->root.x;
+ _ecore_xcb_event_last_root_y = e->root.y;
+
+ ecore_event_add(ECORE_X_EVENT_MOUSE_OUT, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_keymap_notify(xcb_generic_event_t *event EINA_UNUSED)
+{
+// LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ // FIXME: handle this event type
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+}
+
+static void
+_ecore_xcb_event_handle_focus_in(xcb_generic_event_t *event)
+{
+ xcb_focus_in_event_t *ev;
+ Ecore_X_Event_Window_Focus_In *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_focus_in_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In)))) return;
+
+ e->win = ev->event;
+ e->mode = _ecore_xcb_event_mode_get(ev->mode);
+ e->detail = _ecore_xcb_event_detail_get(ev->detail);
+
+ e->time = _ecore_xcb_event_last_time;
+ _ecore_xcb_event_last_time = e->time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_focus_out(xcb_generic_event_t *event)
+{
+ xcb_focus_out_event_t *ev;
+ Ecore_X_Event_Window_Focus_Out *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_focus_out_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out)))) return;
+
+ e->win = ev->event;
+ e->mode = _ecore_xcb_event_mode_get(ev->mode);
+ e->detail = _ecore_xcb_event_detail_get(ev->detail);
+
+ e->time = _ecore_xcb_event_last_time;
+ _ecore_xcb_event_last_time = e->time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_expose(xcb_generic_event_t *event)
+{
+ xcb_expose_event_t *ev;
+ Ecore_X_Event_Window_Damage *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_expose_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)))) return;
+
+ e->win = ev->window;
+ e->time = _ecore_xcb_event_last_time;
+ e->x = ev->x;
+ e->y = ev->y;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->count = ev->count;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_graphics_exposure(xcb_generic_event_t *event)
+{
+ xcb_graphics_exposure_event_t *ev;
+ Ecore_X_Event_Window_Damage *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_graphics_exposure_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)))) return;
+
+ e->win = ev->drawable;
+ e->x = ev->x;
+ e->y = ev->y;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->count = ev->count;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_visibility_notify(xcb_generic_event_t *event)
+{
+ xcb_visibility_notify_event_t *ev;
+ Ecore_X_Event_Window_Visibility_Change *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_visibility_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Visibility_Change))))
+ return;
+
+ e->win = ev->window;
+ e->time = _ecore_xcb_event_last_time;
+ if (ev->state == XCB_VISIBILITY_FULLY_OBSCURED)
+ e->fully_obscured = 1;
+ else
+ e->fully_obscured = 0;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_create_notify(xcb_generic_event_t *event)
+{
+ xcb_create_notify_event_t *ev;
+ Ecore_X_Event_Window_Create *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_create_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Create)))) return;
+
+ e->win = ev->window;
+ e->parent = ev->parent;
+ if (ev->override_redirect)
+ e->override = 1;
+ else
+ e->override = 0;
+ e->x = ev->x;
+ e->y = ev->y;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->border = ev->border_width;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CREATE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_destroy_notify(xcb_generic_event_t *event)
+{
+ xcb_destroy_notify_event_t *ev;
+ Ecore_X_Event_Window_Destroy *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_destroy_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Destroy)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ if (e->win == _ecore_xcb_event_last_window)
+ _ecore_xcb_event_last_window = 0;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DESTROY, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_map_notify(xcb_generic_event_t *event)
+{
+ xcb_map_notify_event_t *ev;
+ Ecore_X_Event_Window_Show *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_map_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Show)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_unmap_notify(xcb_generic_event_t *event)
+{
+ xcb_unmap_notify_event_t *ev;
+ Ecore_X_Event_Window_Hide *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_unmap_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Hide)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_HIDE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_map_request(xcb_generic_event_t *event)
+{
+ xcb_map_request_event_t *ev;
+ Ecore_X_Event_Window_Show_Request *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_map_request_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Show_Request)))) return;
+
+ e->win = ev->window;
+ e->parent = ev->parent;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW_REQUEST, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_reparent_notify(xcb_generic_event_t *event)
+{
+ xcb_reparent_notify_event_t *ev;
+ Ecore_X_Event_Window_Reparent *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_reparent_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Reparent)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ e->parent = ev->parent;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_REPARENT, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_configure_notify(xcb_generic_event_t *event)
+{
+ xcb_configure_notify_event_t *ev;
+ Ecore_X_Event_Window_Configure *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_configure_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Configure)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ e->abovewin = ev->above_sibling;
+ e->x = ev->x;
+ e->y = ev->y;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->border = ev->border_width;
+ e->override = ev->override_redirect;
+ /* send_event is bit 7 (0x80) of response_type */
+ e->from_wm = ((ev->response_type & 0x80) ? 1 : 0);
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_configure_request(xcb_generic_event_t *event)
+{
+ xcb_configure_request_event_t *ev;
+ Ecore_X_Event_Window_Configure_Request *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_configure_request_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Configure_Request))))
+ return;
+
+ e->win = ev->window;
+ e->parent_win = ev->parent;
+ e->abovewin = ev->sibling;
+ e->x = ev->x;
+ e->y = ev->y;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->border = ev->border_width;
+ e->value_mask = ev->value_mask;
+ switch (ev->stack_mode)
+ {
+ case XCB_STACK_MODE_ABOVE:
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ break;
+
+ case XCB_STACK_MODE_BELOW:
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+ break;
+
+ case XCB_STACK_MODE_TOP_IF:
+ e->detail = ECORE_X_WINDOW_STACK_TOP_IF;
+ break;
+
+ case XCB_STACK_MODE_BOTTOM_IF:
+ e->detail = ECORE_X_WINDOW_STACK_BOTTOM_IF;
+ break;
+
+ case XCB_STACK_MODE_OPPOSITE:
+ e->detail = ECORE_X_WINDOW_STACK_OPPOSITE;
+ break;
+ }
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_gravity_notify(xcb_generic_event_t *event EINA_UNUSED)
+{
+/*
+ xcb_gravity_notify_event_t *ev;
+ Ecore_X_Event_Window_Gravity *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_gravity_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Gravity)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_GRAVITY, e, NULL, NULL);
+ */
+}
+
+static void
+_ecore_xcb_event_handle_resize_request(xcb_generic_event_t *event)
+{
+ xcb_resize_request_event_t *ev;
+ Ecore_X_Event_Window_Resize_Request *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_resize_request_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Resize_Request)))) return;
+
+ e->win = ev->window;
+ e->w = ev->width;
+ e->h = ev->height;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_circulate_notify(xcb_generic_event_t *event)
+{
+ xcb_circulate_notify_event_t *ev;
+ Ecore_X_Event_Window_Stack *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_circulate_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Stack)))) return;
+
+ e->win = ev->window;
+ e->event_win = ev->event;
+ if (ev->place == XCB_PLACE_ON_TOP)
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ else
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STACK, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_circulate_request(xcb_generic_event_t *event)
+{
+ xcb_circulate_request_event_t *ev;
+ Ecore_X_Event_Window_Stack_Request *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_circulate_request_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Stack_Request)))) return;
+
+ e->win = ev->window;
+ e->parent = ev->event;
+ if (ev->place == XCB_PLACE_ON_TOP)
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ else
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STACK_REQUEST, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_property_notify(xcb_generic_event_t *event)
+{
+ xcb_property_notify_event_t *ev;
+ Ecore_X_Event_Window_Property *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_property_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Property)))) return;
+
+ e->win = ev->window;
+ e->atom = ev->atom;
+ e->time = ev->time;
+ _ecore_xcb_event_last_time = e->time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_PROPERTY, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_selection_clear(xcb_generic_event_t *event)
+{
+ xcb_selection_clear_event_t *ev;
+ Ecore_X_Event_Selection_Clear *e;
+ Ecore_X_Atom sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_selection_clear_event_t *)event;
+ if (!(e = malloc(sizeof(Ecore_X_Event_Selection_Clear)))) return;
+
+ e->win = ev->owner;
+ e->atom = sel = ev->selection;
+ if (sel == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+ e->time = ev->time;
+
+ ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_selection_request(xcb_generic_event_t *event)
+{
+ xcb_selection_request_event_t *ev;
+ Ecore_X_Event_Selection_Request *e;
+ Ecore_X_Selection_Intern *sd;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_selection_request_event_t *)event;
+ if (!(e = malloc(sizeof(Ecore_X_Event_Selection_Request)))) return;
+
+ e->owner = ev->owner;
+ e->requestor = ev->requestor;
+ e->selection = ev->selection;
+ e->target = ev->target;
+ e->property = ev->property;
+ e->time = ev->time;
+
+ ecore_event_add(ECORE_X_EVENT_SELECTION_REQUEST, e, NULL, NULL);
+
+ if ((sd = _ecore_xcb_selection_get(ev->selection)) &&
+ (sd->win == ev->owner))
+ {
+ Ecore_X_Selection_Intern *si;
+
+ si = _ecore_xcb_selection_get(ev->selection);
+ if (si->data)
+ {
+ Ecore_X_Atom property = XCB_NONE, type;
+ void *data = NULL;
+ int len = 0, typesize = 0;
+
+ type = ev->target;
+ typesize = 8;
+ len = sd->length;
+
+ if (!ecore_x_selection_convert(ev->selection, ev->target,
+ &data, &len, &type, &typesize))
+ property = XCB_NONE;
+ else if (data)
+ {
+ ecore_x_window_prop_property_set(ev->requestor, ev->property,
+ type, typesize, data, len);
+ property = ev->property;
+ free(data);
+ }
+ ecore_x_selection_notify_send(ev->requestor, ev->selection,
+ ev->target, property, ev->time);
+ }
+ }
+}
+
+static void
+_ecore_xcb_event_handle_selection_notify(xcb_generic_event_t *event)
+{
+ xcb_selection_notify_event_t *ev;
+ Ecore_X_Event_Selection_Notify *e;
+ unsigned char *data = NULL;
+ Ecore_X_Atom selection;
+ int num = 0, format = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_selection_notify_event_t *)event;
+ selection = ev->selection;
+ if (ev->target == ECORE_X_ATOM_SELECTION_TARGETS)
+ {
+ format =
+ ecore_x_window_prop_property_get(ev->requestor, ev->property,
+ XCB_ATOM_ATOM, 32, &data, &num);
+ if (!format)
+ {
+ /* fallback if targets handling is not working and try get the
+ * selection directly */
+ xcb_convert_selection(_ecore_xcb_conn, ev->requestor,
+ selection, selection,
+ ECORE_X_ATOM_UTF8_STRING, XCB_CURRENT_TIME);
+ return;
+ }
+ }
+ else
+ format = ecore_x_window_prop_property_get(ev->requestor, ev->property,
+ XCB_GET_PROPERTY_TYPE_ANY, 8,
+ &data, &num);
+
+ e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify));
+ if (!e) return;
+ e->win = ev->requestor;
+ e->time = ev->time;
+ e->atom = selection;
+ e->target = _ecore_xcb_selection_target_get(ev->target);
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ e->selection = ECORE_X_SELECTION_XDND;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+
+ e->data = _ecore_xcb_selection_parse(e->target, data, num, format);
+
+ ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e,
+ _ecore_xcb_event_selection_notify_free, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_colormap_notify(xcb_generic_event_t *event)
+{
+ xcb_colormap_notify_event_t *ev;
+ Ecore_X_Event_Window_Colormap *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_colormap_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Colormap)))) return;
+
+ e->win = ev->window;
+ e->cmap = ev->colormap;
+ if (ev->state == XCB_COLORMAP_STATE_INSTALLED)
+ e->installed = 1;
+ else
+ e->installed = 0;
+ e->time = _ecore_xcb_event_last_time;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_COLORMAP, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_client_message(xcb_generic_event_t *event)
+{
+ xcb_client_message_event_t *ev;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_client_message_event_t *)event;
+
+ /* Special client message event handling here. need to put LOTS of if */
+ /* checks here and generate synthetic events per special message known */
+ /* otherwise generate generic client message event. this would handle*/
+ /* netwm, ICCCM, gnomewm, old kde and mwm hint client message protocols */
+
+ if ((ev->type == ECORE_X_ATOM_WM_PROTOCOLS) && (ev->format == 32) &&
+ (ev->data.data32[0] == ECORE_X_ATOM_WM_DELETE_WINDOW))
+ {
+ Ecore_X_Event_Window_Delete_Request *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Delete_Request))))
+ return;
+ e->win = ev->window;
+ e->time = _ecore_xcb_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL);
+ }
+ else if ((ev->type == ECORE_X_ATOM_NET_WM_MOVERESIZE) &&
+ (ev->format == 32) && (ev->data.data32[2] < 9))
+ {
+ Ecore_X_Event_Window_Move_Resize_Request *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Move_Resize_Request))))
+ return;
+ e->win = ev->window;
+ e->x = ev->data.data32[0];
+ e->y = ev->data.data32[1];
+ e->direction = ev->data.data32[2];
+ e->button = ev->data.data32[3];
+ e->source = ev->data.data32[4];
+ ecore_event_add(ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_ENTER)
+ {
+ Ecore_X_Event_Xdnd_Enter *e;
+ Ecore_X_DND_Target *target;
+
+ DBG("Got Xdnd Enter Event");
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter)))) return;
+ target = _ecore_xcb_dnd_target_get();
+ target->state = ECORE_X_DND_TARGET_ENTERED;
+ target->source = ev->data.data32[0];
+ target->win = ev->window;
+ target->version = (int)(ev->data.data32[1] >> 24);
+ if (target->version > ECORE_X_DND_VERSION)
+ {
+ WRN("DND: Requested version %d but we only support up to %d",
+ target->version, ECORE_X_DND_VERSION);
+ free(e);
+ return;
+ }
+ if (ev->data.data32[1] & 0x1UL)
+ {
+ unsigned char *data;
+ Ecore_X_Atom *types;
+ int num_ret = 0;
+
+ if (!ecore_x_window_prop_property_get(target->source,
+ ECORE_X_ATOM_XDND_TYPE_LIST,
+ ECORE_X_ATOM_ATOM, 32,
+ &data, &num_ret))
+ {
+ WRN("DND: Could not fetch data type list from source window");
+ free(e);
+ return;
+ }
+ types = (Ecore_X_Atom *)data;
+ e->types = calloc(num_ret, sizeof(char *));
+ if (e->types)
+ {
+ int i = 0;
+
+ for (i = 0; i < num_ret; i++)
+ e->types[i] = ecore_x_atom_name_get(types[i]);
+ }
+ e->num_types = num_ret;
+ }
+ else
+ {
+ int i = 0;
+
+ e->types = calloc(3, sizeof(char *));
+ if (e->types)
+ {
+ while ((i < 3) && (ev->data.data32[i + 2]))
+ {
+ e->types[i] =
+ ecore_x_atom_name_get(ev->data.data32[i + 2]);
+ i++;
+ }
+ }
+ e->num_types = i;
+ }
+
+ e->win = target->win;
+ e->source = target->source;
+ ecore_event_add(ECORE_X_EVENT_XDND_ENTER, e,
+ _ecore_xcb_event_xdnd_enter_free, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_POSITION)
+ {
+ Ecore_X_Event_Xdnd_Position *e;
+ Ecore_X_DND_Target *target;
+
+ DBG("Got Xdnd Position Event");
+ target = _ecore_xcb_dnd_target_get();
+ if ((target->source != (Ecore_X_Window)ev->data.data32[0]) ||
+ (target->win != ev->window)) return;
+ target->pos.x = ev->data.data32[2] >> 16;
+ target->pos.y = ev->data.data32[2] & 0xFFFFUL;
+ target->action = ev->data.data32[4];
+ target->time = (target->version >= 1) ?
+ (Ecore_X_Time)ev->data.data32[3] : XCB_CURRENT_TIME;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Position));
+ if (!e) return;
+ e->win = target->win;
+ e->source = target->source;
+ e->position.x = target->pos.x;
+ e->position.y = target->pos.y;
+ e->action = target->action;
+ ecore_event_add(ECORE_X_EVENT_XDND_POSITION, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_STATUS)
+ {
+ Ecore_X_Event_Xdnd_Status *e;
+ Ecore_X_DND_Source *source;
+
+ DBG("Got Xdnd Status Event");
+ source = _ecore_xcb_dnd_source_get();
+ if ((source->win != ev->window) ||
+ (source->dest != (Ecore_X_Window)ev->data.data32[0]))
+ return;
+
+ source->await_status = 0;
+ source->will_accept = ev->data.data32[1] & 0x1UL;
+ source->suppress = (ev->data.data32[1] & 0x2UL) ? 0 : 1;
+ source->rectangle.x = ev->data.data32[2] >> 16;
+ source->rectangle.y = ev->data.data32[2] & 0xFFFFUL;
+ source->rectangle.width = ev->data.data32[3] >> 16;
+ source->rectangle.height = ev->data.data32[3] & 0xFFFFUL;
+ source->accepted_action = ev->data.data32[4];
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Status));
+ if (!e) return;
+ e->win = source->win;
+ e->target = source->dest;
+ e->will_accept = source->will_accept;
+ e->rectangle.x = source->rectangle.x;
+ e->rectangle.y = source->rectangle.y;
+ e->rectangle.width = source->rectangle.width;
+ e->rectangle.height = source->rectangle.height;
+ e->action = source->accepted_action;
+
+ ecore_event_add(ECORE_X_EVENT_XDND_STATUS, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_LEAVE)
+ {
+ Ecore_X_Event_Xdnd_Leave *e;
+ Ecore_X_DND_Target *target;
+
+ DBG("Got Xdnd Leave Event");
+ target = _ecore_xcb_dnd_target_get();
+ if ((target->source != (Ecore_X_Window)ev->data.data32[0]) ||
+ (target->win != ev->window))
+ return;
+ target->state = ECORE_X_DND_TARGET_IDLE;
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Leave));
+ if (!e) return;
+ e->win = ev->window;
+ e->source = (Ecore_X_Window)ev->data.data32[0];
+ ecore_event_add(ECORE_X_EVENT_XDND_LEAVE, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_DROP)
+ {
+ Ecore_X_Event_Xdnd_Drop *e;
+ Ecore_X_DND_Target *target;
+
+ DBG("Got Xdnd Drop Event");
+ target = _ecore_xcb_dnd_target_get();
+ if ((target->source != (Ecore_X_Window)ev->data.data32[0]) ||
+ (target->win != ev->window))
+ return;
+ target->time = (target->version >= 1) ?
+ (Ecore_X_Time)ev->data.data32[2] : _ecore_xcb_event_last_time;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Drop));
+ if (!e) return;
+ e->win = target->win;
+ e->source = target->source;
+ e->action = target->action;
+ e->position.x = target->pos.x;
+ e->position.y = target->pos.y;
+ ecore_event_add(ECORE_X_EVENT_XDND_DROP, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_XDND_FINISHED)
+ {
+ Ecore_X_Event_Xdnd_Finished *e;
+ Ecore_X_DND_Source *source;
+ Eina_Bool completed = EINA_TRUE;
+
+ DBG("Got Xdnd Finished Event");
+ source = _ecore_xcb_dnd_source_get();
+ if ((source->win != ev->window) ||
+ (source->dest != (Ecore_X_Window)ev->data.data32[0]))
+ return;
+ if ((source->version < 5) || (ev->data.data32[1] & 0x1UL))
+ {
+ ecore_x_selection_xdnd_clear();
+ source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+ else if (source->version >= 5)
+ {
+ completed = EINA_FALSE;
+ source->state = ECORE_X_DND_SOURCE_CONVERTING;
+ /* FIXME: Probably need to add a timer to switch back to idle
+ * and discard the selection data */
+ }
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Finished))))
+ return;
+ e->win = source->win;
+ e->target = source->dest;
+ e->completed = completed;
+ if (source->version >= 5)
+ {
+ source->accepted_action = ev->data.data32[2];
+ e->action = source->accepted_action;
+ }
+ else
+ {
+ source->accepted_action = 0;
+ e->action = source->action;
+ }
+ ecore_event_add(ECORE_X_EVENT_XDND_FINISHED, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_NET_WM_STATE)
+ {
+ Ecore_X_Event_Window_State_Request *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request))))
+ return;
+ e->win = ev->window;
+ if (ev->data.data32[0] == 0)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_REMOVE;
+ else if (ev->data.data32[0] == 1)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_ADD;
+ else if (ev->data.data32[0] == 2)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_TOGGLE;
+ else
+ {
+ free(e);
+ return;
+ }
+ e->state[0] = _ecore_xcb_netwm_window_state_get(ev->data.data32[1]);
+ if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN)
+ {
+ /* FIXME */
+ }
+ e->state[1] = _ecore_xcb_netwm_window_state_get(ev->data.data32[2]);
+ if (e->state[1] == ECORE_X_WINDOW_STATE_UNKNOWN)
+ {
+ /* FIXME */
+ }
+ e->source = ev->data.data32[3];
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL);
+ }
+#ifdef OLD_XCB_VERSION
+ else if ((ev->type == ECORE_X_ATOM_WM_CHANGE_STATE) &&
+ (ev->format == 32) && (ev->data.data32[0] == XCB_WM_STATE_ICONIC))
+#else
+ else if ((ev->type == ECORE_X_ATOM_WM_CHANGE_STATE) && (ev->format == 32) &&
+ (ev->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC))
+#endif
+ {
+ Ecore_X_Event_Window_State_Request *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request))))
+ return;
+ e->win = ev->window;
+ e->action = ECORE_X_WINDOW_STATE_ACTION_ADD;
+ e->state[0] = ECORE_X_WINDOW_STATE_ICONIFIED;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL);
+ }
+ else if ((ev->type == ECORE_X_ATOM_NET_WM_DESKTOP) && (ev->format == 32))
+ {
+ Ecore_X_Event_Desktop_Change *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change))))
+ return;
+ e->win = ev->window;
+ e->desk = ev->data.data32[0];
+ e->source = ev->data.data32[1];
+ ecore_event_add(ECORE_X_EVENT_DESKTOP_CHANGE, e, NULL, NULL);
+ }
+ else if (ev->type == ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS)
+ {
+ Ecore_X_Event_Frame_Extents_Request *e;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request))))
+ return;
+ e->win = ev->window;
+ ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL);
+ }
+ else if ((ev->type == ECORE_X_ATOM_WM_PROTOCOLS) &&
+ ((Ecore_X_Atom)ev->data.data32[0] == ECORE_X_ATOM_NET_WM_PING) &&
+ (ev->format == 32))
+ {
+ Ecore_X_Event_Ping *e;
+ Ecore_X_Window root = 0;
+ int count = 0;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Ping)))) return;
+ e->win = ev->window;
+ e->time = ev->data.data32[1];
+ e->event_win = ev->data.data32[2];
+ ecore_event_add(ECORE_X_EVENT_PING, e, NULL, NULL);
+
+ CHECK_XCB_CONN;
+
+ count = xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn));
+ if (count > 1)
+ root = ecore_x_window_root_get(e->win);
+ else
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ if (ev->window != root)
+ {
+ ev->window = root;
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY),
+ (const char *)&ev);
+// ecore_x_flush();
+ }
+ }
+ else if ((ev->type == ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN) &&
+ (ev->format == 8))
+ {
+ _ecore_xcb_netwm_startup_info_begin(ev->window, ev->data.data8[0]);
+ }
+ else if ((ev->type == ECORE_X_ATOM_NET_STARTUP_INFO) && (ev->format == 8))
+ {
+ _ecore_xcb_netwm_startup_info(ev->window, ev->data.data8[0]);
+ }
+ else if ((ev->type == 27777) && (ev->data.data32[0] == 0x7162534) &&
+ (ev->format == 32)) // && (ev->window = _private_window))
+ {
+ if (ev->data.data32[1] == 0x10000001)
+ _ecore_xcb_window_button_grab_remove(ev->data.data32[2]);
+ else if (ev->data.data32[1] == 0x10000002)
+ _ecore_xcb_window_key_grab_remove(ev->data.data32[2]);
+ }
+ else
+ {
+ Ecore_X_Event_Client_Message *e;
+ int i = 0;
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Client_Message))))
+ return;
+
+ e->win = ev->window;
+ e->message_type = ev->type;
+ e->format = ev->format;
+ for (i = 0; i < 5; i++)
+ e->data.l[i] = ev->data.data32[i];
+ ecore_event_add(ECORE_X_EVENT_CLIENT_MESSAGE, e, NULL, NULL);
+ }
+}
+
+static void
+_ecore_xcb_event_handle_mapping_notify(xcb_generic_event_t *event)
+{
+ xcb_mapping_notify_event_t *ev;
+ Ecore_X_Event_Mapping_Change *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+
+ ev = (xcb_mapping_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Mapping_Change)))) return;
+
+ _ecore_xcb_keymap_refresh(ev);
+ _ecore_xcb_modifiers_get();
+
+ switch (ev->request)
+ {
+ case XCB_MAPPING_MODIFIER:
+ e->type = ECORE_X_MAPPING_MODIFIER;
+ break;
+
+ case XCB_MAPPING_KEYBOARD:
+ e->type = ECORE_X_MAPPING_KEYBOARD;
+ break;
+
+ case XCB_MAPPING_POINTER:
+ default:
+ e->type = ECORE_X_MAPPING_MOUSE;
+ break;
+ }
+ e->keycode = ev->first_keycode;
+ e->num = ev->count;
+
+ ecore_event_add(ECORE_X_EVENT_MAPPING_CHANGE, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_damage_notify(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_DAMAGE
+ xcb_damage_notify_event_t *ev;
+ Ecore_X_Event_Damage *e;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_DAMAGE
+ ev = (xcb_damage_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Damage)))) return;
+
+ e->level = ev->level;
+ e->drawable = ev->drawable;
+ e->damage = ev->damage;
+ e->time = ev->timestamp;
+ e->area.x = ev->area.x;
+ e->area.y = ev->area.y;
+ e->area.width = ev->area.width;
+ e->area.height = ev->area.height;
+ e->geometry.x = ev->geometry.x;
+ e->geometry.y = ev->geometry.y;
+ e->geometry.width = ev->geometry.width;
+ e->geometry.height = ev->geometry.height;
+
+ ecore_event_add(ECORE_X_EVENT_DAMAGE_NOTIFY, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_randr_change(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_screen_change_notify_event_t *ev;
+ Ecore_X_Event_Screen_Change *e;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ ev = (xcb_randr_screen_change_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Screen_Change)))) return;
+
+ e->win = ev->request_window;
+ e->root = ev->root;
+ e->size.width = ev->width;
+ e->size.height = ev->height;
+ e->time = ev->timestamp;
+ e->config_time = ev->config_timestamp;
+ e->size.width_mm = ev->mwidth;
+ e->size.height_mm = ev->mheight;
+ e->orientation = ev->rotation;
+ e->subpixel_order = ev->subpixel_order;
+
+ ecore_event_add(ECORE_X_EVENT_SCREEN_CHANGE, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_randr_notify(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_notify_event_t *ev;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ ev = (xcb_randr_notify_event_t *)event;
+ switch (ev->subCode)
+ {
+ case XCB_RANDR_NOTIFY_CRTC_CHANGE:
+ _ecore_xcb_event_handle_randr_crtc_change(event);
+ break;
+
+ case XCB_RANDR_NOTIFY_OUTPUT_CHANGE:
+ _ecore_xcb_event_handle_randr_output_change(event);
+ break;
+
+ case XCB_RANDR_NOTIFY_OUTPUT_PROPERTY:
+ _ecore_xcb_event_handle_randr_output_property_change(event);
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_randr_crtc_change(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_notify_event_t *ev;
+ Ecore_X_Event_Randr_Crtc_Change *e;
+#endif
+
+#ifdef ECORE_XCB_RANDR
+ ev = (xcb_randr_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change))))
+ return;
+
+ e->win = ev->u.cc.window;
+ e->crtc = ev->u.cc.crtc;
+ e->mode = ev->u.cc.mode;
+ e->orientation = ev->u.cc.rotation;
+ e->geo.x = ev->u.cc.x;
+ e->geo.y = ev->u.cc.y;
+ e->geo.w = ev->u.cc.width;
+ e->geo.h = ev->u.cc.height;
+
+ ecore_event_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_randr_output_change(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_notify_event_t *ev;
+ Ecore_X_Event_Randr_Output_Change *e;
+#endif
+
+#ifdef ECORE_XCB_RANDR
+ ev = (xcb_randr_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Change))))
+ return;
+
+ e->win = ev->u.oc.window;
+ e->output = ev->u.oc.output;
+ e->crtc = ev->u.oc.crtc;
+ e->mode = ev->u.oc.mode;
+ e->orientation = ev->u.oc.rotation;
+ e->connection = ev->u.oc.connection;
+ e->subpixel_order = ev->u.oc.subpixel_order;
+
+ ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_randr_output_property_change(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_notify_event_t *ev;
+ Ecore_X_Event_Randr_Output_Property_Notify *e;
+#endif
+
+#ifdef ECORE_XCB_RANDR
+ ev = (xcb_randr_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Property_Notify))))
+ return;
+
+ e->win = ev->u.op.window;
+ e->output = ev->u.op.output;
+ e->property = ev->u.op.atom;
+ e->time = ev->u.op.timestamp;
+ if (ev->u.op.status == XCB_PROPERTY_NEW_VALUE)
+ e->state = ECORE_X_RANDR_PROPERTY_CHANGE_ADD;
+ else
+ e->state = ECORE_X_RANDR_PROPERTY_CHANGE_DEL;
+
+ ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_screensaver_notify(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_screensaver_notify_event_t *ev;
+ Ecore_X_Event_Screensaver_Notify *e;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_SCREENSAVER
+ ev = (xcb_screensaver_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Screensaver_Notify)))) return;
+
+ e->win = ev->window;
+ e->on = EINA_FALSE;
+ if ((ev->state == XCB_SCREENSAVER_STATE_ON) ||
+ (ev->state == XCB_SCREENSAVER_STATE_CYCLE)) e->on = EINA_TRUE;
+ e->time = ev->time;
+
+ ecore_event_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, e, NULL, NULL);
+#endif
+}
+
+#ifdef ECORE_XCB_XGESTURE
+static void
+_ecore_xcb_event_handle_gesture_notify_flick(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_flick_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_Flick *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_flick_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Flick)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->distance = ev->distance;
+ e->duration = ev->duration;
+ e->direction = ev->direction;
+ e->angle = XFixedToDouble(ev->angle);
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_FLICK, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_gesture_notify_pan(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_pan_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_Pan *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_pan_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Pan)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->dx = ev->dx;
+ e->dy = ev->dy;
+ e->distance = ev->distance;
+ e->duration = ev->duration;
+ e->direction = ev->direction;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PAN, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_gesture_notify_pinchrotation(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_pinch_rotation_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_PinchRotation *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_pinch_rotation_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_PinchRotation)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->distance = ev->distance;
+ e->cx = ev->cx;
+ e->cy = ev->cy;
+ e->zoom = XFixedToDouble(ev->zoom);
+ e->angle = XFixedToDouble(ev->angle);
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_gesture_notify_tap(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_tap_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_Tap *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_tap_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Tap)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->cx = ev->cx;
+ e->cy = ev->cy;
+ e->tap_repeat = ev->tap_repeat;
+ e->interval = ev->interval;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAP, e, NULL, NULL);
+}
+
+static void
+_ecore_xcb_event_handle_gesture_notify_tapnhold(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_tap_n_hold_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_TapNHold *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_tap_n_hold_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_TapNHold)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->cx = ev->cx;
+ e->cy = ev->cy;
+ e->interval = ev->interval;
+ e->hold_time = ev->holdtime;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD, e, NULL, NULL);
+}
+
+static void
+ _ecore_xcb_event_handle_gesture_notify_hold(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_hold_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_Hold *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_hold_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Hold)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_fingers = ev->num_finger;
+ e->cx = ev->cx;
+ e->cy = ev->cy;
+ e->hold_time = ev->holdtime;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_HOLD, e, NULL, NULL);
+}
+
+static void
+ _ecore_xcb_event_handle_gesture_notify_group(xcb_generic_event_t *event)
+{
+ xcb_gesture_notify_group_event_t *ev;
+ Ecore_X_Event_Gesture_Notify_Group *e;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__);
+
+ ev = (xcb_gesture_notify_group_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Group)))) return;
+
+ e->win = ev->window;
+ e->time = ev->time;
+ e->subtype = ev->kind;
+ e->num_groups = ev->num_group;
+ e->group_id = ev->groupid;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_GROUP, e, NULL, NULL);
+}
+#endif
+
+#ifdef ECORE_XCB_SHAPE
+static void
+_ecore_xcb_event_handle_shape_change(xcb_generic_event_t *event)
+{
+ xcb_shape_notify_event_t *ev;
+ Ecore_X_Event_Window_Shape *e;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+ ev = (xcb_shape_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Shape)))) return;
+
+ e->win = ev->affected_window;
+ e->time = ev->server_time;
+ switch (ev->shape_kind)
+ {
+ case XCB_SHAPE_SK_BOUNDING:
+ e->type = ECORE_X_SHAPE_BOUNDING;
+ break;
+
+ case XCB_SHAPE_SK_CLIP:
+ e->type = ECORE_X_SHAPE_CLIP;
+ break;
+
+ case XCB_SHAPE_SK_INPUT:
+ e->type = ECORE_X_SHAPE_INPUT;
+ break;
+
+ default:
+ break;
+ }
+ e->x = ev->extents_x;
+ e->y = ev->extents_y;
+ e->w = ev->extents_width;
+ e->h = ev->extents_height;
+ e->shaped = ev->shaped;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHAPE, e, NULL, NULL);
+}
+
+#endif
+
+static void
+_ecore_xcb_event_handle_sync_counter(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_counter_notify_event_t *ev;
+ Ecore_X_Event_Sync_Counter *e;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+
+#ifdef ECORE_XCB_SYNC
+ ev = (xcb_sync_counter_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Sync_Counter)))) return;
+
+ e->time = ev->timestamp;
+
+ ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_sync_alarm(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_alarm_notify_event_t *ev;
+ Ecore_X_Event_Sync_Alarm *e;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_SYNC
+ ev = (xcb_sync_alarm_notify_event_t *)event;
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Sync_Alarm)))) return;
+
+ e->time = ev->timestamp;
+ e->alarm = ev->alarm;
+
+ ecore_event_add(ECORE_X_EVENT_SYNC_ALARM, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_xfixes_selection_notify(xcb_generic_event_t *event)
+{
+#ifdef ECORE_XCB_XFIXES
+ Ecore_X_Event_Fixes_Selection_Notify *e;
+ Ecore_X_Atom sel;
+ xcb_xfixes_selection_notify_event_t *ev;
+#endif
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+#ifdef ECORE_XCB_XFIXES
+ ev = (xcb_xfixes_selection_notify_event_t *)event;
+
+ if (!(e = calloc(1, sizeof(*e)))) return;
+
+ e->win = ev->window;
+ e->owner = ev->owner;
+ e->time = ev->timestamp;
+ e->selection_time = ev->selection_timestamp;
+ e->atom = sel = ev->selection;
+ if (sel == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+ e->reason = ev->subtype;
+
+ ecore_event_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, e, NULL, NULL);
+#endif
+}
+
+static void
+_ecore_xcb_event_handle_xfixes_cursor_notify(xcb_generic_event_t *event EINA_UNUSED)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+// FIXME: TBD
+}
+
+static void
+_ecore_xcb_event_handle_generic_event(xcb_generic_event_t *event)
+{
+ xcb_ge_event_t *ev;
+ Ecore_X_Event_Generic *e;
+
+ ev = (xcb_ge_event_t *)event;
+
+ /* pad0 *IS* extension - bug in xcb */
+ if (ev->pad0 == _ecore_xcb_event_input)
+ {
+ _ecore_xcb_event_handle_input_event(event);
+// FIXME: should we generate generic events as WELL as input events?
+// return;
+ }
+
+ if (!(e = calloc(1, sizeof(Ecore_X_Event_Generic))))
+ return;
+
+ DBG("Handle Generic Event: %d", ev->event_type);
+
+ e->cookie = ev->sequence;
+ /* NB: These are bugs in xcb ge_event structure. The struct should have a
+ * field for extension & data, but does not.
+ *
+ * XCB people have been notified of this issue */
+ e->extension = ev->pad0;
+ /* e->data = ev->pad1; */
+ if (ev->length > 0)
+ {
+ int len = ev->length * sizeof(int);
+ e->data = malloc(len);
+ if (e->data) memcpy(e->data, &(event[1]), len);
+ }
+
+ e->evtype = ev->event_type;
+
+ ecore_event_add(ECORE_X_EVENT_GENERIC, e,
+ _ecore_xcb_event_generic_event_free, e->data);
+}
+
+static void
+_ecore_xcb_event_handle_input_event(xcb_generic_event_t *event)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_input_handle_event(event);
+}
+
+static void
+_ecore_xcb_event_key_press(xcb_generic_event_t *event)
+{
+ Ecore_Event_Key *e;
+ xcb_keysym_t sym = XCB_NO_SYMBOL;
+ xcb_keycode_t keycode = 0;
+ xcb_key_press_event_t *xevent;
+ char *keyname = NULL, *key = NULL;
+ char *compose = NULL;
+ char compose_buffer[256];
+ int val = 0;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+
+ xevent = (xcb_key_press_event_t *)event;
+ keycode = xevent->detail;
+
+ sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, xevent->state);
+ keyname = _ecore_xcb_keymap_keysym_to_string(sym);
+ if (!keyname)
+ {
+ char buff[256];
+
+ snprintf(buff, sizeof(buff), "Keycode-%i", keycode);
+ keyname = buff;
+ }
+
+ val =
+ _ecore_xcb_keymap_lookup_string(keycode, xevent->state, compose_buffer,
+ sizeof(compose_buffer), &sym);
+ if (val > 0)
+ {
+ compose_buffer[val] = 0;
+ compose =
+ eina_str_convert(nl_langinfo(CODESET), "UTF-8", compose_buffer);
+ if (!compose)
+ ERR("Ecore_X cannot convert input key string '%s' to UTF-8. "
+ "Is Eina built with iconv support?", compose_buffer);
+ }
+
+ key = _ecore_xcb_keymap_keysym_to_string(sym);
+ if (!key) key = keyname;
+
+ e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
+ (compose ? strlen(compose) : 0) + 3);
+ if (e)
+ {
+ e->keyname = (char *)(e + 1);
+ e->key = e->keyname + strlen(keyname) + 1;
+
+ e->compose = NULL;
+ if (compose) e->compose = (e->key + strlen(key) + 1);
+ e->string = e->compose;
+
+ strcpy((char *)e->keyname, keyname);
+ strcpy((char *)e->key, key);
+ if (compose) strcpy((char *)e->compose, compose);
+
+ e->modifiers = _ecore_xcb_events_modifiers_get(xevent->state);
+ e->timestamp = xevent->time;
+ e->window = xevent->child ? xevent->child : xevent->event;
+ e->event_window = xevent->event;
+ e->same_screen = xevent->same_screen;
+ e->root_window = xevent->root;
+
+ DBG("Sending Key Down Event: %s", e->keyname);
+ ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL);
+ }
+ _ecore_xcb_event_last_time = xevent->time;
+}
+
+static void
+_ecore_xcb_event_key_release(xcb_generic_event_t *event)
+{
+ Ecore_Event_Key *e;
+ xcb_keysym_t sym = XCB_NO_SYMBOL;
+ xcb_keycode_t keycode = 0;
+ xcb_key_release_event_t *xevent;
+ char *keyname = NULL, *key = NULL;
+ char *compose = NULL;
+ char compose_buffer[256];
+ int val = 0;
+
+ _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+
+ xevent = (xcb_key_release_event_t *)event;
+ keycode = xevent->detail;
+
+ sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, xevent->state);
+ keyname = _ecore_xcb_keymap_keysym_to_string(sym);
+ if (!keyname)
+ {
+ char buff[256];
+
+ snprintf(buff, sizeof(buff), "Keycode-%i", keycode);
+ keyname = buff;
+ }
+
+ val =
+ _ecore_xcb_keymap_lookup_string(keycode, xevent->state, compose_buffer,
+ sizeof(compose_buffer), &sym);
+ if (val > 0)
+ {
+ compose_buffer[val] = 0;
+ compose =
+ eina_str_convert(nl_langinfo(CODESET), "UTF-8", compose_buffer);
+// tmp = compose;
+ }
+
+ key = _ecore_xcb_keymap_keysym_to_string(sym);
+ if (!key) key = keyname;
+
+ e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
+ (compose ? strlen(compose) : 0) + 3);
+ if (e)
+ {
+ e->keyname = (char *)(e + 1);
+ e->key = e->keyname + strlen(keyname) + 1;
+
+ e->compose = NULL;
+ if (compose) e->compose = (e->key + strlen(key) + 1);
+ e->string = e->compose;
+
+ strcpy((char *)e->keyname, keyname);
+ strcpy((char *)e->key, key);
+ if (compose) strcpy((char *)e->compose, compose);
+
+ e->modifiers = _ecore_xcb_events_modifiers_get(xevent->state);
+ e->timestamp = xevent->time;
+ e->window = xevent->child ? xevent->child : xevent->event;
+ e->event_window = xevent->event;
+ e->same_screen = xevent->same_screen;
+ e->root_window = xevent->root;
+
+ ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
+ }
+ _ecore_xcb_event_last_time = xevent->time;
+}
+
+void
+_ecore_xcb_event_mouse_move(uint16_t timestamp,
+ uint16_t modifiers,
+ int16_t x,
+ int16_t y,
+ int16_t root_x,
+ int16_t root_y,
+ xcb_window_t event_win,
+ xcb_window_t win,
+ xcb_window_t root_win,
+ uint8_t same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ int16_t mx,
+ int16_t my,
+ int16_t mrx,
+ int16_t mry)
+{
+ Ecore_Event_Mouse_Move *e;
+ Ecore_Event *event;
+
+ if (!(e = malloc(sizeof(Ecore_Event_Mouse_Move)))) return;
+
+ e->window = win;
+ e->root_window = root_win;
+ e->timestamp = timestamp;
+ e->same_screen = same_screen;
+ e->event_window = event_win;
+ e->modifiers = _ecore_xcb_events_modifiers_get(modifiers);
+ e->x = x;
+ e->y = y;
+ e->root.x = root_x;
+ e->root.y = root_y;
+ e->multi.device = dev;
+ e->multi.radius = ((radx + rady) / 2);
+ e->multi.radius_x = radx;
+ e->multi.radius_y = rady;
+ e->multi.pressure = pressure;
+ e->multi.angle = angle;
+ e->multi.x = mx;
+ e->multi.y = my;
+ e->multi.root.x = mrx;
+ e->multi.root.y = mry;
+
+ event = ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e,
+ _ecore_xcb_event_mouse_move_free, NULL);
+
+ _ecore_xcb_event_last_time = e->timestamp;
+ _ecore_xcb_event_last_window = e->window;
+ _ecore_xcb_event_last_root_x = root_x;
+ _ecore_xcb_event_last_root_y = root_y;
+// _ecore_xcb_event_last_mouse_move_event = event;
+}
+
+static void
+_ecore_xcb_event_mouse_move_free(void *data EINA_UNUSED,
+ void *event)
+{
+ Ecore_Event_Mouse_Move *ev;
+
+ ev = event;
+// if (_ecore_xcb_event_last_mouse_move_event)
+// {
+// _ecore_xcb_event_last_mouse_move = EINA_FALSE;
+// _ecore_xcb_event_last_mouse_move_event = NULL;
+// }
+ if (ev) free(ev);
+}
+
+Ecore_Event_Mouse_Button *
+_ecore_xcb_event_mouse_button(int event,
+ uint16_t timestamp,
+ uint16_t modifiers,
+ xcb_button_t buttons,
+ int16_t x,
+ int16_t y,
+ int16_t root_x,
+ int16_t root_y,
+ xcb_window_t event_win,
+ xcb_window_t win,
+ xcb_window_t root_win,
+ uint8_t same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ int16_t mx,
+ int16_t my,
+ int16_t mrx,
+ int16_t mry)
+{
+ Ecore_Event_Mouse_Button *e;
+ Ecore_X_Mouse_Down_Info *info = NULL;
+
+ if (!(e = malloc(sizeof(Ecore_Event_Mouse_Button)))) return NULL;
+
+ e->window = win;
+ e->root_window = root_win;
+ e->timestamp = timestamp;
+ e->same_screen = same_screen;
+ e->event_window = event_win;
+ e->buttons = buttons;
+ e->modifiers = _ecore_xcb_events_modifiers_get(modifiers);
+ e->double_click = 0;
+ e->triple_click = 0;
+ e->x = x;
+ e->y = y;
+ e->root.x = root_x;
+ e->root.y = root_y;
+
+ if ((info = _ecore_xcb_event_mouse_down_info_get(dev)))
+ {
+ if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) &&
+ (info->did_triple))
+ {
+ info->last_win = 0;
+ info->last_last_win = 0;
+ info->last_event_win = 0;
+ info->last_time = 0;
+ info->last_last_time = 0;
+ }
+ if (event_win == win)
+ {
+ if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN)
+ {
+ if (((int)(timestamp - info->last_time) <=
+ (int)(1000 * _ecore_xcb_double_click_time)) &&
+ (win == info->last_win) &&
+ (event_win == info->last_event_win))
+ {
+ e->double_click = 1;
+ info->did_double = EINA_TRUE;
+ }
+ else
+ {
+ info->did_double = EINA_FALSE;
+ info->did_triple = EINA_FALSE;
+ }
+ if (((int)(timestamp - info->last_last_time) <=
+ (int)(2 * 1000 * _ecore_xcb_double_click_time)) &&
+ (win == info->last_win) &&
+ (win == info->last_last_win) &&
+ (event_win == info->last_event_win) &&
+ (event_win == info->last_last_event_win))
+ {
+ e->triple_click = 1;
+ info->did_triple = EINA_TRUE;
+ }
+ else
+ info->did_triple = EINA_FALSE;
+ }
+ else
+ {
+ if (info->did_double) e->double_click = 1;
+ if (info->did_triple) e->triple_click = 1;
+ }
+ }
+ }
+
+ /* NB: Comment out right now because _ecore_xcb_mouse_up_count is
+ * only used here...nowhere else in the code */
+
+ /* if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && */
+ /* (!e->double_click) && (!e->triple_click)) */
+ /* _ecore_xcb_mouse_up_count = 0; */
+
+ e->multi.device = dev;
+ e->multi.radius = ((radx + rady) / 2);
+ e->multi.radius_x = radx;
+ e->multi.radius_y = rady;
+ e->multi.pressure = pressure;
+ e->multi.angle = angle;
+ e->multi.x = mx;
+ e->multi.y = my;
+ e->multi.root.x = mrx;
+ e->multi.root.y = mry;
+
+ _ecore_xcb_event_last_time = e->timestamp;
+ _ecore_xcb_event_last_window = e->window;
+ _ecore_xcb_event_last_root_x = root_x;
+ _ecore_xcb_event_last_root_y = root_y;
+
+ ecore_event_add(event, e, NULL, NULL);
+
+ if ((info) && (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) &&
+ (win == event_win) && (!info->did_triple))
+ {
+ info->last_last_win = info->last_win;
+ info->last_win = win;
+ info->last_last_event_win = info->last_event_win;
+ info->last_event_win = event_win;
+ info->last_last_time = info->last_time;
+ info->last_time = timestamp;
+ }
+
+ return e;
+}
+
+static Ecore_X_Event_Mode
+_ecore_xcb_event_mode_get(uint8_t mode)
+{
+ switch (mode)
+ {
+ case XCB_NOTIFY_MODE_NORMAL:
+ return ECORE_X_EVENT_MODE_NORMAL;
+
+ case XCB_NOTIFY_MODE_WHILE_GRABBED:
+ return ECORE_X_EVENT_MODE_WHILE_GRABBED;
+
+ case XCB_NOTIFY_MODE_GRAB:
+ return ECORE_X_EVENT_MODE_GRAB;
+
+ case XCB_NOTIFY_MODE_UNGRAB:
+ return ECORE_X_EVENT_MODE_UNGRAB;
+
+ default:
+ return ECORE_X_EVENT_MODE_NORMAL;
+ }
+}
+
+static Ecore_X_Event_Detail
+_ecore_xcb_event_detail_get(uint8_t detail)
+{
+ switch (detail)
+ {
+ case XCB_NOTIFY_DETAIL_ANCESTOR:
+ return ECORE_X_EVENT_DETAIL_ANCESTOR;
+
+ case XCB_NOTIFY_DETAIL_VIRTUAL:
+ return ECORE_X_EVENT_DETAIL_VIRTUAL;
+
+ case XCB_NOTIFY_DETAIL_INFERIOR:
+ return ECORE_X_EVENT_DETAIL_INFERIOR;
+
+ case XCB_NOTIFY_DETAIL_NONLINEAR:
+ return ECORE_X_EVENT_DETAIL_NON_LINEAR;
+
+ case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL:
+ return ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL;
+
+ case XCB_NOTIFY_DETAIL_POINTER:
+ return ECORE_X_EVENT_DETAIL_POINTER;
+
+ case XCB_NOTIFY_DETAIL_POINTER_ROOT:
+ return ECORE_X_EVENT_DETAIL_POINTER_ROOT;
+
+ case XCB_NOTIFY_DETAIL_NONE:
+ default:
+ return ECORE_X_EVENT_DETAIL_ANCESTOR;
+ }
+}
+
+static void
+_ecore_xcb_event_xdnd_enter_free(void *data EINA_UNUSED,
+ void *event)
+{
+ Ecore_X_Event_Xdnd_Enter *e;
+ int i = 0;
+
+ e = event;
+ for (i = 0; i < e->num_types; i++)
+ free(e->types[i]);
+ free(e->types);
+ free(e);
+}
+
+static void
+_ecore_xcb_event_selection_notify_free(void *data EINA_UNUSED,
+ void *event)
+{
+ Ecore_X_Event_Selection_Notify *e;
+ Ecore_X_Selection_Data *sel;
+
+ e = event;
+ if (!(sel = e->data)) return;
+ if (sel->free) sel->free(sel);
+ free(e->target);
+ free(e);
+}
+
+static void
+_ecore_xcb_event_generic_event_free(void *data,
+ void *event)
+{
+ Ecore_X_Event_Generic *e;
+
+ e = (Ecore_X_Event_Generic *)event;
+ if (e->data) free(data);
+ free(e);
+}
+
+static void
+_ecore_xcb_event_mouse_down_info_clear(void)
+{
+ Eina_Inlist *l;
+ Ecore_X_Mouse_Down_Info *info = NULL;
+
+ l = _ecore_xcb_mouse_down_info_list;
+ while (l)
+ {
+ info = EINA_INLIST_CONTAINER_GET(l, Ecore_X_Mouse_Down_Info);
+ l = eina_inlist_remove(l, l);
+ free(info);
+ }
+ _ecore_xcb_mouse_down_info_list = NULL;
+}
+
+static Ecore_X_Mouse_Down_Info *
+_ecore_xcb_event_mouse_down_info_get(int dev)
+{
+ Eina_Inlist *l;
+ Ecore_X_Mouse_Down_Info *info = NULL;
+
+ l = _ecore_xcb_mouse_down_info_list;
+ EINA_INLIST_FOREACH(l, info)
+ if (info->dev == dev) return info;
+
+ if (!(info = calloc(1, sizeof(Ecore_X_Mouse_Down_Info)))) return NULL;
+
+ info->dev = dev;
+ l = eina_inlist_append(l, (Eina_Inlist *)info);
+ _ecore_xcb_mouse_down_info_list = l;
+
+ return info;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_extensions.c b/src/lib/ecore_x/xcb/ecore_xcb_extensions.c
new file mode 100644
index 0000000000..40c10ac05b
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_extensions.c
@@ -0,0 +1,148 @@
+#include "ecore_xcb_private.h"
+
+void
+_ecore_xcb_extensions_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_big_requests_id);
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shm_id);
+
+#ifdef ECORE_XCB_SHAPE
+ _ecore_xcb_shape_init();
+#endif
+
+#ifdef ECORE_XCB_SCREENSAVER
+ _ecore_xcb_screensaver_init();
+#endif
+
+#ifdef ECORE_XCB_SYNC
+ _ecore_xcb_sync_init();
+#endif
+
+#ifdef ECORE_XCB_RANDR
+ _ecore_xcb_randr_init();
+#endif
+
+#ifdef ECORE_XCB_XFIXES
+ _ecore_xcb_xfixes_init();
+#endif
+
+#ifdef ECORE_XCB_DAMAGE
+ _ecore_xcb_damage_init();
+#endif
+
+#ifdef ECORE_XCB_RENDER
+ _ecore_xcb_render_init();
+#endif
+
+#ifdef ECORE_XCB_COMPOSITE
+ _ecore_xcb_composite_init();
+#endif
+
+#ifdef ECORE_XCB_DPMS
+ _ecore_xcb_dpms_init();
+#endif
+
+#ifdef ECORE_XCB_DPMS
+ _ecore_xcb_dpms_init();
+#endif
+
+#ifdef ECORE_XCB_CURSOR
+ _ecore_xcb_cursor_init();
+#endif
+
+#ifdef ECORE_XCB_XINERAMA
+ _ecore_xcb_xinerama_init();
+#endif
+
+#ifdef ECORE_XCB_XINPUT
+ _ecore_xcb_input_init();
+#endif
+
+#ifdef ECORE_XCB_GESTURE
+ _ecore_xcb_gesture_init();
+#endif
+
+/* #ifdef ECORE_XCB_DRI */
+/* _ecore_xcb_dri_init(); */
+/* #endif */
+
+#ifdef ECORE_XCB_XTEST
+ _ecore_xcb_xtest_init();
+#endif
+
+ xcb_prefetch_maximum_request_length(_ecore_xcb_conn);
+}
+
+void
+_ecore_xcb_extensions_finalize(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xcb_get_extension_data(_ecore_xcb_conn, &xcb_big_requests_id);
+ xcb_get_extension_data(_ecore_xcb_conn, &xcb_shm_id);
+
+#ifdef ECORE_XCB_SHAPE
+ _ecore_xcb_shape_finalize();
+#endif
+
+#ifdef ECORE_XCB_SCREENSAVER
+ _ecore_xcb_screensaver_finalize();
+#endif
+
+#ifdef ECORE_XCB_SYNC
+ _ecore_xcb_sync_finalize();
+#endif
+
+#ifdef ECORE_XCB_RANDR
+ _ecore_xcb_randr_finalize();
+#endif
+
+#ifdef ECORE_XCB_XFIXES
+ _ecore_xcb_xfixes_finalize();
+#endif
+
+#ifdef ECORE_XCB_DAMAGE
+ _ecore_xcb_damage_finalize();
+#endif
+
+#ifdef ECORE_XCB_RENDER
+ _ecore_xcb_render_finalize();
+#endif
+
+#ifdef ECORE_XCB_COMPOSITE
+ _ecore_xcb_composite_finalize();
+#endif
+
+#ifdef ECORE_XCB_DPMS
+ _ecore_xcb_dpms_finalize();
+#endif
+
+#ifdef ECORE_XCB_CURSOR
+ _ecore_xcb_cursor_finalize();
+#endif
+
+#ifdef ECORE_XCB_XINERAMA
+ _ecore_xcb_xinerama_finalize();
+#endif
+
+#ifdef ECORE_XCB_XINPUT
+ _ecore_xcb_input_finalize();
+#endif
+
+#ifdef ECORE_XCB_GESTURE
+ _ecore_xcb_gesture_finalize();
+#endif
+
+/* #ifdef ECORE_XCB_DRI */
+/* _ecore_xcb_dri_finalize(); */
+/* #endif */
+
+#ifdef ECORE_XCB_XTEST
+ _ecore_xcb_xtest_finalize();
+#endif
+
+ xcb_get_maximum_request_length(_ecore_xcb_conn);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_gc.c b/src/lib/ecore_x/xcb/ecore_xcb_gc.c
new file mode 100644
index 0000000000..d811b54594
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_gc.c
@@ -0,0 +1,173 @@
+#include "ecore_xcb_private.h"
+
+/**
+ * Creates a new default graphics context associated with the given
+ * drawable.
+ * @param draw Drawable to create graphics context with. If @c 0 is
+ * given instead, the default root window is used.
+ * @param value_mask Bitmask values.
+ * @param value_list List of values. The order of values must be the
+ * same than the corresponding bitmaks.
+ * @return The new default graphics context.
+ */
+EAPI Ecore_X_GC
+ecore_x_gc_new(Ecore_X_Drawable drawable,
+ Ecore_X_GC_Value_Mask value_mask,
+ const unsigned int *value_list)
+{
+ xcb_gcontext_t gc;
+ uint32_t vmask = 0;
+ int i = 0, mask = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!drawable) drawable = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ for (i = 0, mask = 1; i <= 22; i++, mask <<= 1)
+ {
+ switch (mask & value_mask)
+ {
+ case ECORE_X_GC_VALUE_MASK_FUNCTION:
+ vmask |= XCB_GC_FUNCTION;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_PLANE_MASK:
+ vmask |= XCB_GC_PLANE_MASK;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FOREGROUND:
+ vmask |= XCB_GC_FOREGROUND;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_BACKGROUND:
+ vmask |= XCB_GC_BACKGROUND;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_LINE_WIDTH:
+ vmask |= XCB_GC_LINE_WIDTH;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_LINE_STYLE:
+ vmask |= XCB_GC_LINE_STYLE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CAP_STYLE:
+ vmask |= XCB_GC_CAP_STYLE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_JOIN_STYLE:
+ vmask |= XCB_GC_JOIN_STYLE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FILL_STYLE:
+ vmask |= XCB_GC_FILL_STYLE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FILL_RULE:
+ vmask |= XCB_GC_FILL_RULE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE:
+ vmask |= XCB_GC_TILE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_STIPPLE:
+ vmask |= XCB_GC_STIPPLE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X:
+ vmask |= XCB_GC_TILE_STIPPLE_ORIGIN_X;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y:
+ vmask |= XCB_GC_TILE_STIPPLE_ORIGIN_Y;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FONT:
+ vmask |= XCB_GC_FONT;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE:
+ vmask |= XCB_GC_SUBWINDOW_MODE;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES:
+ vmask |= XCB_GC_GRAPHICS_EXPOSURES;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X:
+ vmask |= XCB_GC_CLIP_ORIGIN_X;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y:
+ vmask |= XCB_GC_CLIP_ORIGIN_Y;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_MASK:
+ vmask |= XCB_GC_CLIP_MASK;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_DASH_OFFSET:
+ vmask |= XCB_GC_DASH_OFFSET;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_DASH_LIST:
+ vmask |= XCB_GC_DASH_LIST;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_ARC_MODE:
+ vmask |= XCB_GC_ARC_MODE;
+ break;
+ }
+ }
+
+ gc = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_gc(_ecore_xcb_conn, gc, drawable, vmask, value_list);
+
+// ecore_x_flush();
+ return gc;
+}
+
+/**
+ * Deletes and frees the given graphics context.
+ * @param gc The given graphics context.
+ */
+EAPI void
+ecore_x_gc_free(Ecore_X_GC gc)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_free_gc(_ecore_xcb_conn, gc);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_gc_foreground_set(Ecore_X_GC gc,
+ unsigned long foreground)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = foreground;
+ xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_FOREGROUND, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_gc_background_set(Ecore_X_GC gc,
+ unsigned long background)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = background;
+ xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_BACKGROUND, &list);
+// ecore_x_flush();
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_gesture.c b/src/lib/ecore_x/xcb/ecore_xcb_gesture.c
new file mode 100644
index 0000000000..27c13167af
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_gesture.c
@@ -0,0 +1,203 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_XGESTURE
+# include <xcb/gesture.h>
+# include <xcb/xcb_event.h>
+#endif
+
+/* local variables */
+static Eina_Bool _gesture_available = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_gesture = -1;
+
+void
+_ecore_xcb_gesture_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XGESTURE
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_gesture_id);
+#endif
+}
+
+void
+_ecore_xcb_gesture_finalize(void)
+{
+#ifdef ECORE_XCB_XGESTURE
+ xcb_gesture_query_version_cookie_t cookie;
+ xcb_gesture_query_version_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XGESTURE
+ cookie =
+ xcb_gesture_query_version_unchecked(_ecore_xcb_conn);
+ reply =
+ xcb_gesture_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ _gesture_available = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_gesture_available)
+ {
+ const xcb_query_extension_reply_t *ext_reply;
+
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_gesture_id);
+ if (ext_reply)
+ _ecore_xcb_event_gesture = ext_reply->first_event;
+ }
+#endif
+}
+
+void
+_ecore_xcb_gesture_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+EAPI Eina_Bool
+ecore_x_gesture_supported(void)
+{
+ return _gesture_available;
+}
+
+#ifdef ECORE_XCB_XGESTURE
+EAPI Eina_Bool
+ecore_x_gesture_events_select(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Mask mask)
+#else
+EAPI Eina_Bool
+ecore_x_gesture_events_select(Ecore_X_Window win EINA_UNUSED,
+ Ecore_X_Gesture_Event_Mask mask EINA_UNUSED)
+#endif
+
+{
+#ifdef ECORE_XCB_XGESTURE
+ if (!_gesture_available) return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN
+
+ xcb_gesture_select_events(_ecore_xcb_conn, win, mask);
+
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+#ifdef ECORE_XCB_XGESTURE
+EAPI Ecore_X_Gesture_Event_Mask
+ecore_x_gesture_events_selected_get(Ecore_X_Window win)
+#else
+EAPI Ecore_X_Gesture_Event_Mask
+ecore_x_gesture_events_selected_get(Ecore_X_Window win EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XGESTURE
+ xcb_gesture_get_selected_events_cookie_t ecookie;
+ xcb_gesture_get_selected_events_reply_t *ereply;
+ Ecore_X_Gesture_Event_Mask mask = ECORE_X_GESTURE_EVENT_MASK_NONE;
+
+ if (!_gesture_available) return mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN
+
+ ecookie = xcb_gesture_get_selected_events(_ecore_xcb_conn, win);
+ ereply =
+ xcb_gesture_get_selected_events_reply(_ecore_xcb_conn, ecookie, NULL);
+ if (ereply)
+ {
+ mask = ereply->mask;
+ free(ereply);
+ }
+
+ return mask;
+#else
+ return ECORE_X_GESTURE_EVENT_MASK_NONE;
+#endif
+}
+
+#ifdef ECORE_XCB_XGESTURE
+EAPI Eina_Bool
+ecore_x_gesture_event_grab(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Type type,
+ int num_fingers)
+#else
+EAPI Eina_Bool
+ecore_x_gesture_event_grab(Ecore_X_Window win EINA_UNUSED,
+ Ecore_X_Gesture_Event_Type type EINA_UNUSED,
+ int num_fingers EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XGESTURE
+ Eina_Bool status = EINA_TRUE;
+ xcb_gesture_grab_event_cookie_t ecookie;
+ xcb_gesture_grab_event_reply_t *ereply;
+
+ if (!_gesture_available) return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN
+
+ ecookie =
+ xcb_gesture_grab_event(_ecore_xcb_conn, win, type, num_fingers, 0L);
+ ereply = xcb_gesture_grab_event_reply(_ecore_xcb_conn, ecookie, NULL);
+
+ if (ereply)
+ {
+ if (ereply->status) status = EINA_FALSE;
+ free(ereply);
+ }
+ else
+ status = EINA_FALSE;
+
+ return status;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+#ifdef ECORE_XCB_XGESTURE
+EAPI Eina_Bool
+ecore_x_gesture_event_ungrab(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Type type,
+ int num_fingers)
+#else
+EAPI Eina_Bool
+ecore_x_gesture_event_ungrab(Ecore_X_Window win EINA_UNUSED,
+ Ecore_X_Gesture_Event_Type type EINA_UNUSED,
+ int num_fingers EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XGESTURE
+ Eina_Bool status = EINA_TRUE;
+ xcb_gesture_ungrab_event_cookie_t ecookie;
+ xcb_gesture_ungrab_event_reply_t *ereply;
+
+ if (!_gesture_available) return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN
+
+ ecookie =
+ xcb_gesture_ungrab_event(_ecore_xcb_conn, win, type, num_fingers, 0L);
+ ereply = xcb_gesture_ungrab_event_reply(_ecore_xcb_conn, ecookie, NULL);
+
+ if (ereply)
+ {
+ if (ereply->status) status = EINA_FALSE;
+ free(ereply);
+ }
+ else
+ status = EINA_FALSE;
+
+ return status;
+#else
+ return EINA_FALSE;
+#endif
+}
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_icccm.c b/src/lib/ecore_x/xcb/ecore_xcb_icccm.c
new file mode 100644
index 0000000000..8dea8617d1
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_icccm.c
@@ -0,0 +1,1569 @@
+#include "ecore_xcb_private.h"
+#include <xcb/xcb_icccm.h>
+
+EAPI void
+ecore_x_icccm_init(void)
+{
+}
+
+/**
+ * Sets the WM_COMMAND property for @a win.
+ *
+ * @param win The window.
+ * @param argc Number of arguments.
+ * @param argv Arguments.
+ */
+EAPI void
+ecore_x_icccm_command_set(Ecore_X_Window win,
+ int argc,
+ char **argv)
+{
+ void *buf;
+ char *b;
+ int nbytes, i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ for (i = 0, nbytes = 0; i < argc; i++)
+ if (argv[i]) nbytes += strlen(argv[i]) + 1;
+
+ buf = malloc(sizeof(char) * nbytes);
+ if (!buf) return;
+
+ b = (char *)buf;
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i])
+ {
+ strcpy(b, argv[i]);
+ b += strlen(argv[i]) + 1;
+ }
+ else
+ *b++ = '\0';
+ }
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ ECORE_X_ATOM_WM_COMMAND, ECORE_X_ATOM_STRING, 8,
+ nbytes, buf);
+ free(buf);
+}
+
+/**
+ * Get the WM_COMMAND property for @a win.
+ *
+ * Return the command of a window. String must be free'd when done with.
+ *
+ * @param win The window.
+ * @param argc Number of arguments.
+ * @param argv Arguments.
+ */
+EAPI void
+ecore_x_icccm_command_get(Ecore_X_Window win,
+ int *argc,
+ char ***argv)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int len = 0;
+ char **v, *data, *cp, *start;
+ int c = 0, i = 0, j = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (argc) *argc = 0;
+ if (argv) *argv = NULL;
+
+ cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win,
+ ECORE_X_ATOM_WM_COMMAND,
+ XCB_GET_PROPERTY_TYPE_ANY,
+ 0, 1000000L);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+
+ if ((reply->type != ECORE_X_ATOM_STRING) || (reply->format != 8))
+ {
+ free(reply);
+ return;
+ }
+
+ len = reply->value_len;
+ if (len < 1)
+ {
+ free(reply);
+ return;
+ }
+
+ data = (char *)xcb_get_property_value(reply);
+ if (len && (data[len - 1] == '\0'))
+ len--;
+
+ c = 1;
+ for (cp = (char *)data, i = len; i > 0; cp++, i--)
+ if (*cp == '\0') c++;
+
+ v = (char **)malloc((c + 1) * sizeof(char *));
+ if (!v)
+ {
+ free(reply);
+ return;
+ }
+
+ start = (char *)malloc((len + 1) * sizeof(char));
+ if (!start)
+ {
+ free(reply);
+ free(v);
+ return;
+ }
+
+ memcpy(start, (char *)data, len);
+ start[len] = '\0';
+ for (cp = start, i = len + 1, j = 0; i > 0; cp++, i--)
+ {
+ if (*cp == '\0')
+ {
+ v[j] = start;
+ start = (cp + 1);
+ j++;
+ }
+ }
+
+ if (c < 1)
+ {
+ free(reply);
+ free(v);
+ return;
+ }
+
+ if (argc) *argc = c;
+
+ if (argv)
+ {
+ (*argv) = malloc(c * sizeof(char *));
+ if (!*argv)
+ {
+ free(reply);
+ free(v);
+ if (argc) *argc = 0;
+ return;
+ }
+
+ for (i = 0; i < c; i++)
+ {
+ if (v[i])
+ (*argv)[i] = strdup(v[i]);
+ else
+ (*argv)[i] = strdup("");
+ }
+ }
+
+ free(reply);
+ free(v);
+}
+
+EAPI char *
+ecore_x_icccm_title_get(Ecore_X_Window win)
+{
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_t prop;
+#else
+ xcb_icccm_get_text_property_reply_t prop;
+#endif
+ uint8_t ret = 0;
+ char *title = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return NULL;
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_name_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_name_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#else
+ cookie = xcb_icccm_get_wm_name_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_name_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#endif
+ if (ret == 0) return NULL;
+ if (prop.name_len < 1)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return NULL;
+ }
+
+ if (!(title = malloc((prop.name_len + 1) * sizeof(char *))))
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return NULL;
+ }
+ memcpy(title, prop.name, sizeof(char *) * prop.name_len);
+ title[prop.name_len] = '\0';
+
+ if (prop.encoding != ECORE_X_ATOM_UTF8_STRING)
+ {
+ Ecore_Xcb_Textproperty tp;
+ int count = 0;
+ char **list = NULL;
+ Eina_Bool ret = EINA_FALSE;
+
+ tp.value = strdup(title);
+ tp.nitems = prop.name_len;
+ tp.encoding = prop.encoding;
+#ifdef HAVE_ICONV
+ ret = _ecore_xcb_utf8_textproperty_to_textlist(&tp, &list, &count);
+#else
+ ret = _ecore_xcb_mb_textproperty_to_textlist(&tp, &list, &count);
+#endif
+ if (ret)
+ {
+ if (count > 0)
+ title = strdup(list[0]);
+
+ if (list) free(list);
+ }
+ }
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return title;
+}
+
+EAPI void
+ecore_x_icccm_title_set(Ecore_X_Window win,
+ const char *title)
+{
+ Ecore_Xcb_Textproperty prop;
+ char *list[1];
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!title) return;
+
+ prop.value = NULL;
+ list[0] = strdup(title);
+
+#ifdef HAVE_ICONV
+ ret = _ecore_xcb_utf8_textlist_to_textproperty(list, 1, XcbUTF8StringStyle,
+ &prop);
+#else
+ ret = _ecore_xcb_mb_textlist_to_textproperty(list, 1, XcbStdICCTextStyle,
+ &prop);
+#endif
+
+ if (ret)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ strlen(prop.value), prop.value);
+#else
+ xcb_icccm_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, 8,
+ strlen(prop.value), prop.value);
+#endif
+ if (prop.value) free(prop.value);
+ }
+ else
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ strlen(title), title);
+#else
+ xcb_icccm_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, 8,
+ strlen(title), title);
+#endif
+ free(list[0]);
+}
+
+/**
+ * Get a window name & class.
+ * @param win The window
+ * @param n The name string
+ * @param c The class string
+ *
+ * Get a window name * class
+ */
+EAPI void
+ecore_x_icccm_name_class_get(Ecore_X_Window win,
+ char **name,
+ char **class)
+{
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_class_reply_t prop;
+#else
+ xcb_icccm_get_wm_class_reply_t prop;
+#endif
+ uint8_t ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (name) *name = NULL;
+ if (class) *class = NULL;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_class_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_class_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#else
+ cookie = xcb_icccm_get_wm_class_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_class_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#endif
+ if (ret == 0) return;
+
+ if (name) *name = strdup(prop.instance_name);
+ if (class) *class = strdup(prop.class_name);
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_class_reply_wipe(&prop);
+#else
+ xcb_icccm_get_wm_class_reply_wipe(&prop);
+#endif
+}
+
+/**
+ * Set a window name & class.
+ * @param win The window
+ * @param n The name string
+ * @param c The class string
+ *
+ * Set a window name * class
+ */
+EAPI void
+ecore_x_icccm_name_class_set(Ecore_X_Window win,
+ const char *name,
+ const char *class)
+{
+ char *class_string, *s;
+ int length_name, length_class;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ length_name = strlen(name);
+ length_class = strlen(class);
+ class_string =
+ (char *)malloc(sizeof(char) * (length_name + length_class + 2));
+ if (!class_string) return;
+
+ s = class_string;
+ if (length_name)
+ {
+ strcpy(s, name);
+ s += length_name + 1;
+ }
+ else
+ *s++ = '\0';
+
+ if (length_class)
+ strcpy(s, class);
+ else
+ *s = '\0';
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ ECORE_X_ATOM_WM_CLASS, ECORE_X_ATOM_STRING, 8,
+ length_name + length_class + 2, (void *)class_string);
+ free(class_string);
+}
+
+/**
+ * Specify that a window is transient for another top-level window and should be handled accordingly.
+ * @param win the transient window
+ * @param forwin the toplevel window
+ */
+EAPI void
+ecore_x_icccm_transient_for_set(Ecore_X_Window win,
+ Ecore_X_Window forwindow)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ ECORE_X_ATOM_WM_TRANSIENT_FOR, ECORE_X_ATOM_WINDOW, 32,
+ 1, (void *)&forwindow);
+}
+
+/**
+ * Remove the transient_for setting from a window.
+ * @param win The window
+ */
+EAPI void
+ecore_x_icccm_transient_for_unset(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_TRANSIENT_FOR);
+}
+
+/**
+ * Get the window this window is transient for, if any.
+ * @param win The window to check
+ * @return The window ID of the top-level window, or 0 if the property does not exist.
+ */
+EAPI Ecore_X_Window
+ecore_x_icccm_transient_for_get(Ecore_X_Window win)
+{
+ Ecore_X_Window forwin = 0;
+ xcb_get_property_cookie_t cookie;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_transient_for_unchecked(_ecore_xcb_conn, win);
+ xcb_get_wm_transient_for_reply(_ecore_xcb_conn, cookie, &forwin, NULL);
+#else
+ cookie = xcb_icccm_get_wm_transient_for_unchecked(_ecore_xcb_conn, win);
+ xcb_icccm_get_wm_transient_for_reply(_ecore_xcb_conn, cookie, &forwin, NULL);
+#endif
+
+ return forwin;
+}
+
+/**
+ * Get the window role.
+ * @param win The window
+ * @return The window's role string.
+ */
+EAPI char *
+ecore_x_icccm_window_role_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE);
+}
+
+/**
+ * Set the window role hint.
+ * @param win The window
+ * @param role The role string
+ */
+EAPI void
+ecore_x_icccm_window_role_set(Ecore_X_Window win,
+ const char *role)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE, role);
+}
+
+/**
+ * Get the window's client leader.
+ * @param win The window
+ * @return The window's client leader window, or 0 if unset
+ */
+EAPI Ecore_X_Window
+ecore_x_icccm_client_leader_get(Ecore_X_Window win)
+{
+ Ecore_X_Window leader;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
+ &leader, 1) > 0)
+ return leader;
+
+ return 0;
+}
+
+/**
+ * Set the window's client leader.
+ * @param win The window
+ * @param l The client leader window
+ *
+ * All non-transient top-level windows created by an app other than
+ * the main window must have this property set to the app's main window.
+ */
+EAPI void
+ecore_x_icccm_client_leader_set(Ecore_X_Window win,
+ Ecore_X_Window leader)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
+ &leader, 1);
+}
+
+EAPI Ecore_X_Window_State_Hint
+ecore_x_icccm_state_get(Ecore_X_Window win)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ Ecore_X_Window_State_Hint hint = ECORE_X_WINDOW_STATE_HINT_NONE;
+ uint8_t *prop;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie =
+ xcb_get_property_unchecked(_ecore_xcb_conn, 0, win,
+ ECORE_X_ATOM_WM_STATE, ECORE_X_ATOM_WM_STATE,
+ 0L, 0x7fffffff);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return hint;
+ if ((reply->type == 0) || (reply->format != 8) || (reply->value_len != 2))
+ {
+ free(reply);
+ return hint;
+ }
+
+ prop = (uint8_t *)xcb_get_property_value(reply);
+#ifdef OLD_XCB_VERSION
+ switch (prop[0])
+ {
+ case XCB_WM_STATE_WITHDRAWN:
+ hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ break;
+
+ case XCB_WM_STATE_NORMAL:
+ hint = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ break;
+
+ case XCB_WM_STATE_ICONIC:
+ hint = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ break;
+
+ default:
+ break;
+ }
+#else
+ switch (prop[0])
+ {
+ case XCB_ICCCM_WM_STATE_WITHDRAWN:
+ hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ break;
+
+ case XCB_ICCCM_WM_STATE_NORMAL:
+ hint = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ break;
+
+ case XCB_ICCCM_WM_STATE_ICONIC:
+ hint = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ free(reply);
+ return hint;
+}
+
+EAPI void
+ecore_x_icccm_state_set(Ecore_X_Window win,
+ Ecore_X_Window_State_Hint state)
+{
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_t hints;
+#else
+ xcb_icccm_wm_hints_t hints;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_set_none(&hints);
+
+ hints.flags = XCB_WM_HINT_STATE;
+
+ if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ xcb_wm_hints_set_withdrawn(&hints);
+ else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ xcb_wm_hints_set_normal(&hints);
+ else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ xcb_wm_hints_set_iconic(&hints);
+
+ xcb_set_wm_hints(_ecore_xcb_conn, win, &hints);
+#else
+ xcb_icccm_wm_hints_set_none(&hints);
+
+ hints.flags = XCB_ICCCM_WM_HINT_STATE;
+
+ if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ xcb_icccm_wm_hints_set_withdrawn(&hints);
+ else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ xcb_icccm_wm_hints_set_normal(&hints);
+ else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ xcb_icccm_wm_hints_set_iconic(&hints);
+
+ xcb_icccm_set_wm_hints(_ecore_xcb_conn, win, &hints);
+#endif
+}
+
+EAPI void
+ecore_x_icccm_delete_window_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ ECORE_X_EVENT_MASK_NONE,
+ ECORE_X_ATOM_WM_DELETE_WINDOW, t, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_icccm_hints_set(Ecore_X_Window win,
+ Eina_Bool accepts_focus,
+ Ecore_X_Window_State_Hint initial_state,
+ Ecore_X_Pixmap icon_pixmap,
+ Ecore_X_Pixmap icon_mask,
+ Ecore_X_Window icon_window,
+ Ecore_X_Window window_group,
+ Eina_Bool is_urgent)
+{
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_t hints;
+#else
+ xcb_icccm_wm_hints_t hints;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_set_none(&hints);
+ xcb_wm_hints_set_input(&hints, accepts_focus);
+
+ if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ xcb_wm_hints_set_withdrawn(&hints);
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ xcb_wm_hints_set_normal(&hints);
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ xcb_wm_hints_set_iconic(&hints);
+
+ if (icon_pixmap != 0) xcb_wm_hints_set_icon_pixmap(&hints, icon_pixmap);
+ if (icon_mask != 0) xcb_wm_hints_set_icon_mask(&hints, icon_mask);
+ if (icon_window != 0) xcb_wm_hints_set_icon_window(&hints, icon_window);
+ if (window_group != 0) xcb_wm_hints_set_window_group(&hints, window_group);
+ if (is_urgent) xcb_wm_hints_set_urgency(&hints);
+
+ xcb_set_wm_hints(_ecore_xcb_conn, win, &hints);
+#else
+ xcb_icccm_wm_hints_set_none(&hints);
+ xcb_icccm_wm_hints_set_input(&hints, accepts_focus);
+
+ if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ xcb_icccm_wm_hints_set_withdrawn(&hints);
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ xcb_icccm_wm_hints_set_normal(&hints);
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ xcb_icccm_wm_hints_set_iconic(&hints);
+
+ if (icon_pixmap != 0)
+ xcb_icccm_wm_hints_set_icon_pixmap(&hints, icon_pixmap);
+ if (icon_mask != 0)
+ xcb_icccm_wm_hints_set_icon_mask(&hints, icon_mask);
+ if (icon_window != 0)
+ xcb_icccm_wm_hints_set_icon_window(&hints, icon_window);
+ if (window_group != 0)
+ xcb_icccm_wm_hints_set_window_group(&hints, window_group);
+ if (is_urgent)
+ xcb_icccm_wm_hints_set_urgency(&hints);
+
+ xcb_icccm_set_wm_hints(_ecore_xcb_conn, win, &hints);
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_icccm_hints_get(Ecore_X_Window win,
+ Eina_Bool *accepts_focus,
+ Ecore_X_Window_State_Hint *initial_state,
+ Ecore_X_Pixmap *icon_pixmap,
+ Ecore_X_Pixmap *icon_mask,
+ Ecore_X_Window *icon_window,
+ Ecore_X_Window *window_group,
+ Eina_Bool *is_urgent)
+{
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_t hints;
+#else
+ xcb_icccm_wm_hints_t hints;
+#endif
+ uint8_t ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (accepts_focus) *accepts_focus = EINA_TRUE;
+ if (initial_state) *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ if (icon_pixmap) *icon_pixmap = 0;
+ if (icon_mask) *icon_mask = 0;
+ if (icon_window) *icon_window = 0;
+ if (window_group) *window_group = 0;
+ if (is_urgent) *is_urgent = EINA_FALSE;
+
+#ifdef OLD_XCB_VERSION
+ xcb_wm_hints_set_none(&hints);
+ cookie = xcb_get_wm_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL);
+#else
+ xcb_icccm_wm_hints_set_none(&hints);
+ cookie = xcb_icccm_get_wm_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL);
+#endif
+ if (!ret) return EINA_FALSE;
+
+#ifdef OLD_XCB_VERSION
+ if ((hints.flags & XCB_WM_HINT_INPUT) && (accepts_focus))
+#else
+ if ((hints.flags & XCB_ICCCM_WM_HINT_INPUT) && (accepts_focus))
+#endif
+ {
+ if (hints.input)
+ *accepts_focus = EINA_TRUE;
+ else
+ *accepts_focus = EINA_FALSE;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if ((hints.flags & XCB_WM_HINT_STATE) && (initial_state))
+ {
+ if (hints.initial_state == XCB_WM_STATE_WITHDRAWN)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ else if (hints.initial_state == XCB_WM_STATE_NORMAL)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ else if (hints.initial_state == XCB_WM_STATE_ICONIC)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ }
+
+ if ((hints.flags & XCB_WM_HINT_ICON_PIXMAP) && (icon_pixmap))
+ *icon_pixmap = hints.icon_pixmap;
+
+ if ((hints.flags & XCB_WM_HINT_ICON_MASK) && (icon_mask))
+ *icon_mask = hints.icon_mask;
+
+ if ((hints.flags & XCB_WM_HINT_ICON_WINDOW) && (icon_window))
+ *icon_window = hints.icon_window;
+
+ if ((hints.flags & XCB_WM_HINT_WINDOW_GROUP) && (window_group))
+ *window_group = hints.window_group;
+
+ if ((hints.flags & XCB_WM_HINT_X_URGENCY) && (is_urgent))
+ *is_urgent = EINA_TRUE;
+#else
+ if ((hints.flags & XCB_ICCCM_WM_HINT_STATE) && (initial_state))
+ {
+ if (hints.initial_state == XCB_ICCCM_WM_STATE_WITHDRAWN)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ else if (hints.initial_state == XCB_ICCCM_WM_STATE_NORMAL)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ else if (hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ }
+
+ if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP) && (icon_pixmap))
+ *icon_pixmap = hints.icon_pixmap;
+
+ if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_MASK) && (icon_mask))
+ *icon_mask = hints.icon_mask;
+
+ if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) && (icon_window))
+ *icon_window = hints.icon_window;
+
+ if ((hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) && (window_group))
+ *window_group = hints.window_group;
+
+ if ((hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) && (is_urgent))
+ *is_urgent = EINA_TRUE;
+#endif
+
+ return EINA_TRUE;
+}
+
+/**
+ * Get a window icon name.
+ * @param win The window
+ * @return The windows icon name string
+ *
+ * Return the icon name of a window. String must be free'd when done with.
+ */
+EAPI char *
+ecore_x_icccm_icon_name_get(Ecore_X_Window win)
+{
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_t prop;
+#else
+ xcb_icccm_get_text_property_reply_t prop;
+#endif
+ uint8_t ret = 0;
+ char *tmp = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return NULL;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_icon_name_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_icon_name_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#else
+ cookie = xcb_icccm_get_wm_icon_name_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_icon_name_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#endif
+ if (ret == 0) return NULL;
+
+ if (prop.name_len < 1)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return NULL;
+ }
+
+ if (!(tmp = malloc((prop.name_len + 1) * sizeof(char *))))
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return NULL;
+ }
+ memcpy(tmp, prop.name, sizeof(char *) * prop.name_len);
+ tmp[prop.name_len] = '\0';
+
+ if (prop.encoding != ECORE_X_ATOM_UTF8_STRING)
+ {
+ Ecore_Xcb_Textproperty tp;
+ int count = 0;
+ char **list = NULL;
+ Eina_Bool ret = EINA_FALSE;
+
+ tp.value = strdup(tmp);
+ tp.nitems = prop.name_len;
+ tp.encoding = prop.encoding;
+#ifdef HAVE_ICONV
+ ret = _ecore_xcb_utf8_textproperty_to_textlist(&tp, &list, &count);
+#else
+ ret = _ecore_xcb_mb_textproperty_to_textlist(&tp, &list, &count);
+#endif
+ if (ret)
+ {
+ if (count > 0)
+ tmp = strdup(list[0]);
+
+ if (list) free(list);
+ }
+ }
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return tmp;
+}
+
+/**
+ * Set a window icon name.
+ * @param win The window
+ * @param t The icon name string
+ *
+ * Set a window icon name
+ */
+EAPI void
+ecore_x_icccm_icon_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ Ecore_Xcb_Textproperty prop;
+ char *list[1];
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!win) || (!name)) return;
+
+ prop.value = NULL;
+ list[0] = strdup(name);
+
+#ifdef HAVE_ICONV
+ ret = _ecore_xcb_utf8_textlist_to_textproperty(list, 1, XcbUTF8StringStyle,
+ &prop);
+#else
+ ret = _ecore_xcb_mb_textlist_to_textproperty(list, 1, XcbStdICCTextStyle,
+ &prop);
+#endif
+
+ if (ret)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ strlen(prop.value), prop.value);
+#else
+ xcb_icccm_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ 8, strlen(prop.value), prop.value);
+#endif
+ if (prop.value) free(prop.value);
+ }
+ else
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ strlen(name), name);
+#else
+ xcb_icccm_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING,
+ 8, strlen(name), name);
+#endif
+
+ free(list[0]);
+}
+
+EAPI void
+ecore_x_icccm_iconic_request_send(Ecore_X_Window win,
+ Ecore_X_Window root)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_WM_CHANGE_STATE;
+#ifdef OLD_XCB_VERSION
+ ev.data.data32[0] = XCB_WM_STATE_ICONIC;
+#else
+ ev.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
+#endif
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT),
+ (const char *)&ev);
+// ecore_x_flush();
+}
+
+/**
+ * Set or unset a wm protocol property.
+ * @param win The Window
+ * @param protocol The protocol to enable/disable
+ * @param on On/Off
+ */
+EAPI void
+ecore_x_icccm_protocol_set(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol,
+ Eina_Bool on)
+{
+ Ecore_X_Atom proto;
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_t protos;
+#else
+ xcb_icccm_get_wm_protocols_reply_t protos;
+#endif
+ int i = 0, count = 0, set = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return;
+ proto = _ecore_xcb_atoms_wm_protocol[protocol];
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto);
+ if (!xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL))
+#else
+ cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto);
+ if (!xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL))
+#endif
+ count = 0;
+ else
+ count = protos.atoms_len;
+
+ for (i = 0; i < count; i++)
+ {
+ if (protos.atoms[i] == proto)
+ {
+ set = 1;
+ break;
+ }
+ }
+
+ if (on)
+ {
+ if (!set)
+ {
+ Ecore_X_Atom *atoms = NULL;
+
+ atoms = malloc((count + 1) * sizeof(Ecore_X_Atom));
+ if (atoms)
+ {
+ for (i = 0; i < count; i++)
+ atoms[i] = protos.atoms[i];
+ atoms[count] = proto;
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_protocols(_ecore_xcb_conn,
+ ECORE_X_ATOM_WM_PROTOCOLS,
+ win, count, atoms);
+#else
+ xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS,
+ count, atoms);
+#endif
+ free(atoms);
+ }
+ }
+ }
+ else
+ {
+ if (set)
+ {
+ for (i = 0; i < count; i++)
+ {
+ if (protos.atoms[i] == proto)
+ {
+ int j = 0;
+
+ for (j = (i + 1); j < count; j++)
+ protos.atoms[j - 1] = protos.atoms[j];
+ if (count > 1)
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_protocols(_ecore_xcb_conn,
+ ECORE_X_ATOM_WM_PROTOCOLS,
+ win, count - 1, protos.atoms);
+#else
+ xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS,
+ count - 1, protos.atoms);
+#endif
+ else
+ ecore_x_window_prop_property_del(win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&protos);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+#endif
+}
+
+/**
+ * Determines whether a protocol is set for a window.
+ * @param win The Window
+ * @param protocol The protocol to query
+ * @return 1 if the protocol is set, else 0.
+ */
+EAPI Eina_Bool
+ecore_x_icccm_protocol_isset(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol)
+{
+ Ecore_X_Atom proto;
+ Eina_Bool ret = EINA_FALSE;
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_t reply;
+#else
+ xcb_icccm_get_wm_protocols_reply_t reply;
+#endif
+ uint8_t val = 0;
+ unsigned int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return EINA_FALSE;
+
+ proto = _ecore_xcb_atoms_wm_protocol[protocol];
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto);
+ val = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &reply, NULL);
+#else
+ cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto);
+ val = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &reply, NULL);
+#endif
+ if (!val) return EINA_FALSE;
+
+ for (i = 0; i < reply.atoms_len; i++)
+ if (reply.atoms[i] == proto)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&reply);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&reply);
+#endif
+
+ return ret;
+}
+
+/**
+ * Set protocol atoms explicitly
+ * @param win The Window
+ * @param protos An array of protocol atoms
+ * @param num the number of members of the array
+ */
+EAPI void
+ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,
+ Ecore_X_Atom *protos,
+ int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num > 0)
+#ifdef OLD_XCB_VERSION
+ xcb_set_wm_protocols(_ecore_xcb_conn, ECORE_X_ATOM_WM_PROTOCOLS,
+ win, num, protos);
+#else
+ xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS, num, protos);
+#endif
+ else
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_PROTOCOLS);
+}
+
+EAPI Eina_Bool
+ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,
+ Eina_Bool *request_pos,
+ Ecore_X_Gravity *gravity,
+ int *min_w,
+ int *min_h,
+ int *max_w,
+ int *max_h,
+ int *base_w,
+ int *base_h,
+ int *step_x,
+ int *step_y,
+ double *min_aspect,
+ double *max_aspect)
+{
+ xcb_size_hints_t hints;
+ xcb_get_property_cookie_t cookie;
+ uint8_t ret = 0;
+ int32_t minw = 0, minh = 0;
+ int32_t maxw = 32767, maxh = 32767;
+ int32_t basew = -1, baseh = -1;
+ int32_t stepx = -1, stepy = -1;
+ double mina = 0.0, maxa = 0.0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (request_pos) *request_pos = EINA_FALSE;
+ if (gravity) *gravity = ECORE_X_GRAVITY_NW;
+ if (min_w) *min_w = minw;
+ if (min_h) *min_h = minh;
+ if (max_w) *max_w = maxw;
+ if (max_h) *max_h = maxh;
+ if (base_w) *base_w = basew;
+ if (base_h) *base_h = baseh;
+ if (step_x) *step_x = stepx;
+ if (step_y) *step_y = stepy;
+ if (min_aspect) *min_aspect = mina;
+ if (max_aspect) *max_aspect = maxa;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL);
+#else
+ cookie = xcb_icccm_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie,
+ &hints, NULL);
+#endif
+ if (!ret) return EINA_FALSE;
+
+#ifdef OLD_XCB_VERSION
+ if ((hints.flags & XCB_SIZE_HINT_US_POSITION) ||
+ (hints.flags & XCB_SIZE_HINT_P_POSITION))
+#else
+ if ((hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION) ||
+ (hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION))
+#endif
+ {
+ if (request_pos) *request_pos = EINA_TRUE;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY)
+#endif
+ {
+ if (gravity) *gravity = hints.win_gravity;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
+#endif
+ {
+ minw = hints.min_width;
+ minh = hints.min_height;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
+#endif
+ {
+ maxw = hints.max_width;
+ maxh = hints.max_height;
+ if (maxw < minw) maxw = minw;
+ if (maxh < minh) maxh = minh;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_BASE_SIZE)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE)
+#endif
+ {
+ basew = hints.base_width;
+ baseh = hints.base_height;
+ if (basew > minw) minw = basew;
+ if (baseh > minh) minh = baseh;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)
+#endif
+ {
+ stepx = hints.width_inc;
+ stepy = hints.height_inc;
+ if (stepx < 1) stepx = 1;
+ if (stepy < 1) stepy = 1;
+ }
+
+#ifdef OLD_XCB_VERSION
+ if (hints.flags & XCB_SIZE_HINT_P_ASPECT)
+#else
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT)
+#endif
+ {
+ if (hints.min_aspect_den > 0)
+ mina = ((double)hints.min_aspect_num) / ((double)hints.min_aspect_den);
+
+ if (hints.max_aspect_den > 0)
+ maxa = ((double)hints.max_aspect_num) / ((double)hints.max_aspect_den);
+ }
+
+ if (min_w) *min_w = minw;
+ if (min_h) *min_h = minh;
+ if (max_w) *max_w = maxw;
+ if (max_h) *max_h = maxh;
+ if (base_w) *base_w = basew;
+ if (base_h) *base_h = baseh;
+ if (step_x) *step_x = stepx;
+ if (step_y) *step_y = stepy;
+ if (min_aspect) *min_aspect = mina;
+ if (max_aspect) *max_aspect = maxa;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,
+ Eina_Bool request_pos,
+ Ecore_X_Gravity gravity,
+ int min_w,
+ int min_h,
+ int max_w,
+ int max_h,
+ int base_w,
+ int base_h,
+ int step_x,
+ int step_y,
+ double min_aspect,
+ double max_aspect)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_size_hints_t hints;
+ uint8_t ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL);
+#else
+ cookie = xcb_icccm_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie,
+ &hints, NULL);
+#endif
+ if (!ret) memset(&hints, 0, sizeof(xcb_size_hints_t));
+
+ hints.flags = 0;
+
+#ifdef OLD_XCB_VERSION
+ if (request_pos)
+ hints.flags |= XCB_SIZE_HINT_US_POSITION;
+
+ if (gravity != ECORE_X_GRAVITY_NW)
+ xcb_size_hints_set_win_gravity(&hints, gravity);
+ if ((min_w > 0) || (min_h > 0))
+ xcb_size_hints_set_min_size(&hints, min_w, min_h);
+ if ((max_w > 0) || (max_h > 0))
+ xcb_size_hints_set_max_size(&hints, max_w, max_h);
+ if ((base_w > 0) || (base_h > 0))
+ xcb_size_hints_set_base_size(&hints, base_w, base_h);
+ if ((step_x > 1) || (step_y > 1))
+ xcb_size_hints_set_resize_inc(&hints, step_x, step_y);
+ if ((min_aspect > 0.0) || (max_aspect > 0.0))
+ xcb_size_hints_set_aspect(&hints,
+ (int32_t)(min_aspect * 10000), 10000,
+ (int32_t)(max_aspect * 10000), 10000);
+
+ xcb_set_wm_normal_hints(_ecore_xcb_conn, win, &hints);
+#else
+ if (request_pos)
+ hints.flags |= XCB_ICCCM_SIZE_HINT_US_POSITION;
+
+ if (gravity != ECORE_X_GRAVITY_NW)
+ xcb_icccm_size_hints_set_win_gravity(&hints, gravity);
+ if ((min_w > 0) || (min_h > 0))
+ xcb_icccm_size_hints_set_min_size(&hints, min_w, min_h);
+ if ((max_w > 0) || (max_h > 0))
+ xcb_icccm_size_hints_set_max_size(&hints, max_w, max_h);
+ if ((base_w > 0) || (base_h > 0))
+ xcb_icccm_size_hints_set_base_size(&hints, base_w, base_h);
+ if ((step_x > 1) || (step_y > 1))
+ xcb_icccm_size_hints_set_resize_inc(&hints, step_x, step_y);
+ if ((min_aspect > 0.0) || (max_aspect > 0.0))
+ xcb_icccm_size_hints_set_aspect(&hints,
+ (int32_t)(min_aspect * 10000), 10000,
+ (int32_t)(max_aspect * 10000), 10000);
+
+ xcb_icccm_set_wm_normal_hints(_ecore_xcb_conn, win, &hints);
+#endif
+}
+
+EAPI void
+ecore_x_icccm_move_resize_send(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ xcb_configure_notify_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ memset(&ev, 0, sizeof(xcb_configure_notify_event_t));
+
+ ev.response_type = XCB_CONFIGURE_NOTIFY;
+ ev.event = win;
+ ev.window = win;
+ ev.above_sibling = XCB_NONE;
+ ev.x = x;
+ ev.y = y;
+ ev.width = w;
+ ev.height = h;
+ ev.border_width = 0;
+ ev.override_redirect = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *)&ev);
+// ecore_x_flush();
+}
+
+/**
+ * Get a window client machine string.
+ * @param win The window
+ * @return The windows client machine string
+ *
+ * Return the client machine of a window. String must be free'd when done with.
+ */
+EAPI char *
+ecore_x_icccm_client_machine_get(Ecore_X_Window win)
+{
+ xcb_get_property_cookie_t cookie;
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_t prop;
+#else
+ xcb_icccm_get_text_property_reply_t prop;
+#endif
+ uint8_t ret = 0;
+ char *tmp = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_client_machine_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_get_wm_client_machine_reply(_ecore_xcb_conn, cookie, &prop, NULL);
+#else
+ cookie = xcb_icccm_get_wm_client_machine_unchecked(_ecore_xcb_conn, win);
+ ret = xcb_icccm_get_wm_client_machine_reply(_ecore_xcb_conn, cookie,
+ &prop, NULL);
+#endif
+ if (ret == 0) return NULL;
+
+ tmp = malloc((prop.name_len + 1) * sizeof(char *));
+ if (!tmp)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+ return NULL;
+ }
+ memcpy(tmp, prop.name, sizeof(char *) * prop.name_len);
+ tmp[prop.name_len] = '\0';
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_text_property_reply_wipe(&prop);
+#else
+ xcb_icccm_get_text_property_reply_wipe(&prop);
+#endif
+
+ return tmp;
+}
+
+EAPI void
+ecore_x_icccm_take_focus_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ XCB_EVENT_MASK_NO_EVENT,
+ ECORE_X_ATOM_WM_TAKE_FOCUS, t, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_icccm_save_yourself_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ XCB_EVENT_MASK_NO_EVENT,
+ ECORE_X_ATOM_WM_SAVE_YOURSELF, t, 0, 0, 0);
+}
+
+/**
+ * Add a subwindow to the list of windows that need a different colormap installed.
+ * @param win The toplevel window
+ * @param subwin The subwindow to be added to the colormap windows list
+ */
+EAPI void
+ecore_x_icccm_colormap_window_set(Ecore_X_Window win,
+ Ecore_X_Window subwin)
+{
+ int num = 0, i = 0;
+ unsigned char *odata = NULL, *data = NULL;
+ Ecore_X_Window *newset = NULL, *oldset = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ ECORE_X_ATOM_WINDOW, 32, &odata, &num))
+ {
+ if (!(newset = calloc(1, sizeof(Ecore_X_Window)))) return;
+ newset[0] = subwin;
+ num = 1;
+ data = (unsigned char *)newset;
+ }
+ else
+ {
+ if (!(newset = calloc(num + 1, sizeof(Ecore_X_Window)))) return;
+ oldset = (Ecore_X_Window *)odata;
+ for (i = 0; i < num; i++)
+ {
+ if (oldset[i] == subwin)
+ {
+ if (odata) free(odata);
+ odata = NULL;
+ free(newset);
+ return;
+ }
+ newset[i] = oldset[i];
+ }
+ newset[num++] = subwin;
+ if (odata) free(odata);
+ data = (unsigned char *)newset;
+ }
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ ECORE_X_ATOM_WINDOW, 32, data, num);
+ free(newset);
+}
+
+/**
+ * Remove a window from the list of colormap windows.
+ * @param win The toplevel window
+ * @param subwin The window to be removed from the colormap window list.
+ */
+EAPI void
+ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,
+ Ecore_X_Window subwin)
+{
+ int num = 0, i = 0, j = 0, k = 0;
+ unsigned char *odata = NULL, *data = NULL;
+ Ecore_X_Window *newset = NULL, *oldset = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ ECORE_X_ATOM_WINDOW, 32, &odata, &num))
+ return;
+
+ oldset = (Ecore_X_Window *)odata;
+ for (i = 0; i < num; i++)
+ {
+ if (oldset[i] == subwin)
+ {
+ if (num == 1)
+ {
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS);
+ if (odata) free(odata);
+ odata = NULL;
+ return;
+ }
+ else
+ {
+ newset = calloc(num - 1, sizeof(Ecore_X_Window));
+ data = (unsigned char *)newset;
+ for (j = 0; j < num; ++j)
+ if (oldset[j] != subwin)
+ newset[k++] = oldset[j];
+
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ ECORE_X_ATOM_WINDOW, 32, data, k);
+ if (odata) free(odata);
+ odata = NULL;
+ free(newset);
+ return;
+ }
+ }
+ }
+ if (odata) free(odata);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_image.c b/src/lib/ecore_x/xcb/ecore_xcb_image.c
new file mode 100644
index 0000000000..8e221101b0
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_image.c
@@ -0,0 +1,738 @@
+#include "ecore_xcb_private.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <xcb/xcb_event.h>
+#include <xcb/shm.h>
+
+struct _Ecore_X_Image
+{
+ xcb_shm_segment_info_t shminfo;
+ xcb_image_t *xim;
+ Ecore_X_Visual vis;
+ int depth, w, h;
+ int bpl, bpp, rows;
+ unsigned char *data;
+ Eina_Bool shm : 1;
+};
+
+/* local function prototypes */
+static void _ecore_xcb_image_shm_check(void);
+static void _ecore_xcb_image_shm_create(Ecore_X_Image *im);
+static xcb_format_t *_ecore_xcb_image_find_format(const xcb_setup_t *setup,
+ uint8_t depth);
+
+/* local variables */
+static int _ecore_xcb_image_shm_can = -1;
+
+EAPI Ecore_X_Image *
+ecore_x_image_new(int w,
+ int h,
+ Ecore_X_Visual vis,
+ int depth)
+{
+ Ecore_X_Image *im;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(im = calloc(1, sizeof(Ecore_X_Image)))) return NULL;
+ im->w = w;
+ im->h = h;
+ im->vis = vis;
+ im->depth = depth;
+ _ecore_xcb_image_shm_check();
+ im->shm = _ecore_xcb_image_shm_can;
+ return im;
+}
+
+EAPI void
+ecore_x_image_free(Ecore_X_Image *im)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!im) return;
+ if (im->shm)
+ {
+ if (im->xim)
+ {
+ xcb_shm_detach(_ecore_xcb_conn, im->shminfo.shmseg);
+ xcb_image_destroy(im->xim);
+ shmdt(im->shminfo.shmaddr);
+ shmctl(im->shminfo.shmid, IPC_RMID, 0);
+ }
+ }
+ else if (im->xim)
+ {
+ if (im->xim->data) free(im->xim->data);
+ im->xim->data = NULL;
+ xcb_image_destroy(im->xim);
+ }
+
+ free(im);
+// ecore_x_flush();
+}
+
+EAPI Eina_Bool
+ecore_x_image_get(Ecore_X_Image *im,
+ Ecore_X_Drawable draw,
+ int x,
+ int y,
+ int sx,
+ int sy,
+ int w,
+ int h)
+{
+ Eina_Bool ret = EINA_TRUE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (im->shm)
+ {
+ if (!im->xim) _ecore_xcb_image_shm_create(im);
+ if (!im->xim) return EINA_FALSE;
+
+ if ((sx == 0) && (w == im->w))
+ {
+ im->xim->data = (uint8_t *)im->data + (im->xim->stride * sy) +
+ (sx * im->bpp);
+ im->xim->width = w;
+ im->xim->height = h;
+
+ ecore_x_grab();
+ if (!xcb_image_shm_get(_ecore_xcb_conn, draw, im->xim,
+ im->shminfo, x, y, 0xffffffff))
+ {
+ DBG("\tImage Shm Get Failed");
+ ret = EINA_FALSE;
+ }
+ ecore_x_ungrab();
+ ecore_x_sync(); // needed
+ }
+ else
+ {
+ Ecore_X_Image *tim;
+
+ tim = ecore_x_image_new(w, h, im->vis, im->depth);
+ if (tim)
+ {
+ ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h);
+ if (ret)
+ {
+ unsigned char *spixels, *pixels;
+ int sbpp = 0, sbpl = 0, srows = 0;
+ int bpp = 0, bpl = 0, rows = 0;
+
+ spixels =
+ ecore_x_image_data_get(tim, &sbpl, &srows, &sbpp);
+ pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp);
+ if ((spixels) && (pixels))
+ {
+ unsigned char *p, *sp;
+ int r = 0;
+
+ p = (pixels + (sy * bpl) + (sx * bpp));
+ sp = spixels;
+ for (r = srows; r > 0; r--)
+ {
+ memcpy(p, sp, sbpl);
+ p += bpl;
+ sp += sbpl;
+ }
+ }
+ }
+ ecore_x_image_free(tim);
+ }
+ }
+ }
+ else
+ {
+ ret = EINA_FALSE;
+ ecore_x_grab();
+ im->xim =
+ xcb_image_get(_ecore_xcb_conn, draw, x, y, w, h,
+ 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
+ if (!im->xim) ret = EINA_FALSE;
+ ecore_x_ungrab();
+ ecore_x_sync(); // needed
+
+ if (im->xim)
+ {
+ im->data = (unsigned char *)im->xim->data;
+ im->bpl = im->xim->stride;
+ im->rows = im->xim->height;
+ if (im->xim->bpp <= 8)
+ im->bpp = 1;
+ else if (im->xim->bpp <= 16)
+ im->bpp = 2;
+ else
+ im->bpp = 4;
+ }
+ }
+
+ return ret;
+}
+
+EAPI void *
+ecore_x_image_data_get(Ecore_X_Image *im,
+ int *bpl,
+ int *rows,
+ int *bpp)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!im) return NULL;
+ if (!im->xim) _ecore_xcb_image_shm_create(im);
+ if (!im->xim) return NULL;
+
+ if (bpl) *bpl = im->bpl;
+ if (rows) *rows = im->rows;
+ if (bpp) *bpp = im->bpp;
+
+ return im->data;
+}
+
+EAPI void
+ecore_x_image_put(Ecore_X_Image *im,
+ Ecore_X_Drawable draw,
+ Ecore_X_GC gc,
+ int x,
+ int y,
+ int sx,
+ int sy,
+ int w,
+ int h)
+{
+ Ecore_X_GC tgc = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!gc)
+ {
+ uint32_t mask, values[1];
+
+ tgc = xcb_generate_id(_ecore_xcb_conn);
+ mask = XCB_GC_SUBWINDOW_MODE;
+ values[0] = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS;
+ xcb_create_gc(_ecore_xcb_conn, tgc, draw, mask, values);
+ gc = tgc;
+ }
+ if (!im->xim) _ecore_xcb_image_shm_create(im);
+ if (im->xim)
+ {
+ if (im->shm)
+ xcb_shm_put_image(_ecore_xcb_conn, draw, gc, im->xim->width,
+ im->xim->height, sx, sy, w, h, x, y,
+ im->xim->depth, im->xim->format, 0,
+ im->shminfo.shmseg,
+ im->xim->data - im->shminfo.shmaddr);
+// xcb_image_shm_put(_ecore_xcb_conn, draw, gc, im->xim,
+// im->shminfo, sx, sy, x, y, w, h, 0);
+ else
+ xcb_image_put(_ecore_xcb_conn, draw, gc, im->xim, sx, sy, 0);
+ }
+ if (tgc) ecore_x_gc_free(tgc);
+ ecore_x_sync();
+}
+
+EAPI Eina_Bool
+ecore_x_image_is_argb32_get(Ecore_X_Image *im)
+{
+ xcb_visualtype_t *vis;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ vis = (xcb_visualtype_t *)im->vis;
+ if (!im->xim) _ecore_xcb_image_shm_create(im);
+
+ if (((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) ||
+ (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR)) &&
+ (im->depth >= 24) && (vis->red_mask == 0xff0000) &&
+ (vis->green_mask == 0x00ff00) && (vis->blue_mask == 0x0000ff))
+ {
+#ifdef WORDS_BIGENDIAN
+ if (im->xim->byte_order == XCB_IMAGE_ORDER_MSB_FIRST) return EINA_TRUE;
+#else
+ if (im->xim->byte_order == XCB_IMAGE_ORDER_LSB_FIRST) return EINA_TRUE;
+#endif
+ }
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_image_to_argb_convert(void *src,
+ int sbpp,
+ int sbpl,
+ Ecore_X_Colormap c,
+ Ecore_X_Visual v,
+ int x,
+ int y,
+ int w,
+ int h,
+ unsigned int *dst,
+ int dbpl,
+ int dx,
+ int dy)
+{
+ xcb_visualtype_t *vis;
+ uint32_t *cols;
+ int n = 0, nret = 0, i, row, mode = 0;
+ unsigned int pal[256], r, g, b;
+ enum
+ {
+ rgbnone = 0,
+ rgb565,
+ bgr565,
+ rgbx555,
+ argbx888,
+ abgrx888,
+ rgba888x,
+ bgra888x,
+ argbx666
+ };
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ sbpp *= 8;
+
+ vis = (xcb_visualtype_t *)v;
+ n = vis->colormap_entries;
+ if ((n <= 256) &&
+ ((vis->_class == XCB_VISUAL_CLASS_PSEUDO_COLOR) ||
+ (vis->_class == XCB_VISUAL_CLASS_STATIC_COLOR) ||
+ (vis->_class == XCB_VISUAL_CLASS_GRAY_SCALE) ||
+ (vis->_class == XCB_VISUAL_CLASS_STATIC_GRAY)))
+ {
+ xcb_query_colors_cookie_t cookie;
+ xcb_query_colors_reply_t *reply;
+
+ if (!c)
+ {
+ c = (xcb_colormap_t)((xcb_screen_t *)
+ _ecore_xcb_screen)->default_colormap;
+ }
+
+ cols = alloca(n * sizeof(uint32_t));
+ for (i = 0; i < n; i++)
+ cols[i] = i;
+
+ cookie = xcb_query_colors_unchecked(_ecore_xcb_conn, c, n, cols);
+ reply = xcb_query_colors_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ xcb_rgb_iterator_t iter;
+ xcb_rgb_t *ret;
+
+ iter = xcb_query_colors_colors_iterator(reply);
+ ret = xcb_query_colors_colors(reply);
+ if (ret)
+ {
+ for (i = 0; iter.rem; xcb_rgb_next(&iter), i++)
+ {
+ pal[i] = 0xff000000 |
+ ((iter.data->red >> 8) << 16) |
+ ((iter.data->green >> 8) << 8) |
+ ((iter.data->blue >> 8));
+ }
+ nret = n;
+ }
+ free(reply);
+ }
+ }
+ else if ((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) ||
+ (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR))
+ {
+ if ((vis->red_mask == 0x00ff0000) &&
+ (vis->green_mask == 0x0000ff00) &&
+ (vis->blue_mask == 0x000000ff))
+ mode = argbx888;
+ else if ((vis->red_mask == 0x000000ff) &&
+ (vis->green_mask == 0x0000ff00) &&
+ (vis->blue_mask == 0x00ff0000))
+ mode = abgrx888;
+ else if ((vis->red_mask == 0xff000000) &&
+ (vis->green_mask == 0x00ff0000) &&
+ (vis->blue_mask == 0x0000ff00))
+ mode = rgba888x;
+ else if ((vis->red_mask == 0x0000ff00) &&
+ (vis->green_mask == 0x00ff0000) &&
+ (vis->blue_mask == 0xff000000))
+ mode = bgra888x;
+ else if ((vis->red_mask == 0x0003f000) &&
+ (vis->green_mask == 0x00000fc0) &&
+ (vis->blue_mask == 0x0000003f))
+ mode = argbx666;
+ else if ((vis->red_mask == 0x0000f800) &&
+ (vis->green_mask == 0x000007e0) &&
+ (vis->blue_mask == 0x0000001f))
+ mode = rgb565;
+ else if ((vis->red_mask == 0x0000001f) &&
+ (vis->green_mask == 0x000007e0) &&
+ (vis->blue_mask == 0x0000f800))
+ mode = bgr565;
+ else if ((vis->red_mask == 0x00007c00) &&
+ (vis->green_mask == 0x000003e0) &&
+ (vis->blue_mask == 0x0000001f))
+ mode = rgbx555;
+ else
+ return EINA_FALSE;
+ }
+ for (row = 0; row < h; row++)
+ {
+ unsigned char *s8;
+ unsigned short *s16;
+ unsigned int *s32, *dp, *de;
+
+ dp = ((unsigned int *)(((unsigned char *)dst) +
+ ((dy + row) * dbpl))) + dx;
+ de = dp + w;
+ switch (sbpp)
+ {
+ case 8:
+ s8 = ((unsigned char *)(((unsigned char *)src) +
+ ((y + row) * sbpl))) + x;
+ if (nret > 0)
+ {
+ while (dp < de)
+ {
+ *dp = pal[*s8];
+ s8++; dp++;
+ }
+ }
+ else
+ return EINA_FALSE;
+ break;
+
+ case 16:
+ s16 = ((unsigned short *)(((unsigned char *)src) +
+ ((y + row) * sbpl))) + x;
+ switch (mode)
+ {
+ case rgb565:
+ while (dp < de)
+ {
+ r = (*s16 & 0xf800) << 8;
+ g = (*s16 & 0x07e0) << 5;
+ b = (*s16 & 0x001f) << 3;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ case bgr565:
+ while (dp < de)
+ {
+ r = (*s16 & 0x001f) << 19;
+ g = (*s16 & 0x07e0) << 5;
+ b = (*s16 & 0xf800) >> 8;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ case rgbx555:
+ while (dp < de)
+ {
+ r = (*s16 & 0x7c00) << 9;
+ g = (*s16 & 0x03e0) << 6;
+ b = (*s16 & 0x001f) << 3;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 5) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ break;
+
+ case 24:
+ case 32:
+ s32 = ((unsigned int *)(((unsigned char *)src) +
+ ((y + row) * sbpl))) + x;
+ switch (mode)
+ {
+ case argbx888:
+ while (dp < de)
+ {
+ *dp = 0xff000000 | *s32;
+ s32++; dp++;
+ }
+ break;
+
+ case abgrx888:
+ while (dp < de)
+ {
+ r = *s32 & 0x000000ff;
+ g = *s32 & 0x0000ff00;
+ b = *s32 & 0x00ff0000;
+ *dp = 0xff000000 | (r << 16) | (g) | (b >> 16);
+ s32++; dp++;
+ }
+ break;
+
+ case rgba888x:
+ while (dp < de)
+ {
+ *dp = 0xff000000 | (*s32 >> 8);
+ s32++; dp++;
+ }
+ break;
+
+ case bgra888x:
+ while (dp < de)
+ {
+ r = *s32 & 0x0000ff00;
+ g = *s32 & 0x00ff0000;
+ b = *s32 & 0xff000000;
+ *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24);
+ s32++; dp++;
+ }
+ break;
+
+ case argbx666:
+ while (dp < de)
+ {
+ r = (*s32 & 0x3f000) << 6;
+ g = (*s32 & 0x00fc0) << 4;
+ b = (*s32 & 0x0003f) << 2;
+ r |= (r >> 6) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 6);
+ *dp = 0xff000000 | r | g | b;
+ s32++; dp++;
+ }
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ break;
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ }
+ return EINA_TRUE;
+}
+
+/* local functions */
+static void
+_ecore_xcb_image_shm_check(void)
+{
+// xcb_shm_query_version_reply_t *reply;
+ xcb_shm_segment_info_t shminfo;
+ xcb_shm_get_image_cookie_t cookie;
+ xcb_shm_get_image_reply_t *ireply;
+ xcb_image_t *img = 0;
+ uint8_t depth = 0;
+
+ if (_ecore_xcb_image_shm_can != -1) return;
+ CHECK_XCB_CONN;
+
+ /* reply = */
+ /* xcb_shm_query_version_reply(_ecore_xcb_conn, */
+ /* xcb_shm_query_version(_ecore_xcb_conn), NULL); */
+ /* if (!reply) */
+ /* { */
+ /* _ecore_xcb_image_shm_can = 0; */
+ /* return; */
+ /* } */
+
+ /* if ((reply->major_version < 1) || */
+ /* ((reply->major_version == 1) && (reply->minor_version == 0))) */
+ /* { */
+ /* _ecore_xcb_image_shm_can = 0; */
+ /* free(reply); */
+ /* return; */
+ /* } */
+
+ /* free(reply); */
+
+ depth = ((xcb_screen_t *)_ecore_xcb_screen)->root_depth;
+
+ ecore_x_sync(); // needed
+
+ img = _ecore_xcb_image_create_native(1, 1, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ depth, NULL, ~0, NULL);
+ if (!img)
+ {
+ _ecore_xcb_image_shm_can = 0;
+ return;
+ }
+
+ shminfo.shmid =
+ shmget(IPC_PRIVATE, img->stride * img->height, (IPC_CREAT | 0666));
+ if (shminfo.shmid == (uint32_t)-1)
+ {
+ xcb_image_destroy(img);
+ _ecore_xcb_image_shm_can = 0;
+ return;
+ }
+
+ shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
+ img->data = shminfo.shmaddr;
+ if (img->data == (uint8_t *)-1)
+ {
+ xcb_image_destroy(img);
+ _ecore_xcb_image_shm_can = 0;
+ return;
+ }
+
+ shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn);
+ xcb_shm_attach(_ecore_xcb_conn, shminfo.shmseg, shminfo.shmid, 0);
+
+ cookie =
+ xcb_shm_get_image(_ecore_xcb_conn,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ 0, 0, img->width, img->height,
+ 0xffffffff, img->format,
+ shminfo.shmseg, img->data - shminfo.shmaddr);
+
+ ecore_x_sync(); // needed
+
+ ireply = xcb_shm_get_image_reply(_ecore_xcb_conn, cookie, NULL);
+ if (ireply)
+ {
+ _ecore_xcb_image_shm_can = 1;
+ free(ireply);
+ }
+ else
+ _ecore_xcb_image_shm_can = 0;
+
+ xcb_shm_detach(_ecore_xcb_conn, shminfo.shmseg);
+ xcb_image_destroy(img);
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+}
+
+static void
+_ecore_xcb_image_shm_create(Ecore_X_Image *im)
+{
+ CHECK_XCB_CONN;
+
+ im->xim =
+ _ecore_xcb_image_create_native(im->w, im->h, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ im->depth, NULL, ~0, NULL);
+ if (!im->xim) return;
+
+ im->shminfo.shmid = shmget(IPC_PRIVATE, im->xim->size, (IPC_CREAT | 0666));
+ if (im->shminfo.shmid == (uint32_t)-1)
+ {
+ xcb_image_destroy(im->xim);
+ return;
+ }
+
+ im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0);
+ im->xim->data = im->shminfo.shmaddr;
+ if ((!im->xim->data) || (im->xim->data == (uint8_t *)-1))
+ {
+ DBG("Shm Create No Image Data");
+ xcb_image_destroy(im->xim);
+ shmdt(im->shminfo.shmaddr);
+ shmctl(im->shminfo.shmid, IPC_RMID, 0);
+ return;
+ }
+
+ im->shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn);
+ xcb_shm_attach(_ecore_xcb_conn, im->shminfo.shmseg, im->shminfo.shmid, 0);
+
+ im->data = (unsigned char *)im->xim->data;
+ im->bpl = im->xim->stride;
+ im->rows = im->xim->height;
+ if (im->xim->bpp <= 8)
+ im->bpp = 1;
+ else if (im->xim->bpp <= 16)
+ im->bpp = 2;
+ else
+ im->bpp = 4;
+}
+
+xcb_image_t *
+_ecore_xcb_image_create_native(int w,
+ int h,
+ xcb_image_format_t format,
+ uint8_t depth,
+ void *base,
+ uint32_t bytes,
+ uint8_t *data)
+{
+ static uint8_t dpth = 0;
+ static xcb_format_t *fmt = NULL;
+ const xcb_setup_t *setup;
+ xcb_image_format_t xif;
+
+ CHECK_XCB_CONN;
+
+ /* NB: We cannot use xcb_image_create_native as it only creates images
+ * using MSB_FIRST, so this routine recreates that function and uses
+ * the endian-ness of the server setup */
+ setup = xcb_get_setup(_ecore_xcb_conn);
+ xif = format;
+
+ if ((xif == XCB_IMAGE_FORMAT_Z_PIXMAP) && (depth == 1))
+ xif = XCB_IMAGE_FORMAT_XY_PIXMAP;
+
+ if (dpth != depth)
+ {
+ dpth = depth;
+ fmt = _ecore_xcb_image_find_format(setup, depth);
+ if (!fmt) return 0;
+ }
+
+ switch (xif)
+ {
+ case XCB_IMAGE_FORMAT_XY_BITMAP:
+ if (depth != 1) return 0;
+
+ case XCB_IMAGE_FORMAT_XY_PIXMAP:
+ case XCB_IMAGE_FORMAT_Z_PIXMAP:
+ return xcb_image_create(w, h, xif,
+ fmt->scanline_pad,
+ fmt->depth, fmt->bits_per_pixel,
+ setup->bitmap_format_scanline_unit,
+ setup->image_byte_order,
+ setup->bitmap_format_bit_order,
+ base, bytes, data);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static xcb_format_t *
+_ecore_xcb_image_find_format(const xcb_setup_t *setup,
+ uint8_t depth)
+{
+ xcb_format_t *fmt, *fmtend;
+
+ CHECK_XCB_CONN;
+
+ fmt = xcb_setup_pixmap_formats(setup);
+ fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
+ for (; fmt != fmtend; ++fmt)
+ if (fmt->depth == depth)
+ return fmt;
+
+ return 0;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_input.c b/src/lib/ecore_x/xcb/ecore_xcb_input.c
new file mode 100644
index 0000000000..6cf3ebf6e6
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_input.c
@@ -0,0 +1,274 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_XINPUT
+# include <xcb/xinput.h>
+# include <xcb/xcb_event.h>
+#endif
+
+/* FIXME: this is a guess. can't find defines for touch events in xcb libs
+ * online */
+/* these are not yet defined in xcb support for xi2 - so manually create */
+#ifndef XCB_INPUT_DEVICE_TOUCH_BEGIN
+#define XCB_INPUT_DEVICE_TOUCH_BEGIN 18
+#endif
+#ifndef XCB_INPUT_DEVICE_TOUCH_END
+#define XCB_INPUT_DEVICE_TOUCH_END 19
+#endif
+#ifndef XCB_INPUT_DEVICE_TOUCH_UPDATE
+#define XCB_INPUT_DEVICE_TOUCH_UPDATE 21
+#endif
+
+#ifndef XCB_INPUT_POINTER_EMULATED_MASK
+#define XCB_INPUT_POINTER_EMULATED_MASK (1 << 16)
+#endif
+
+/* local variables */
+static Eina_Bool _input_avail = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_input = 0;
+
+void
+_ecore_xcb_input_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XINPUT
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_input_id);
+#endif
+}
+
+void
+_ecore_xcb_input_finalize(void)
+{
+#ifdef ECORE_XCB_XINPUT
+ xcb_input_get_extension_version_cookie_t cookie;
+ xcb_input_get_extension_version_reply_t *reply;
+ char buff[128];
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XINPUT
+ cookie =
+ xcb_input_get_extension_version_unchecked(_ecore_xcb_conn, 127, buff);
+ reply =
+ xcb_input_get_extension_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ _input_avail = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_input_avail)
+ {
+ const xcb_query_extension_reply_t *ext_reply;
+
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_input_id);
+ if (ext_reply)
+ _ecore_xcb_event_input = ext_reply->first_event;
+ }
+#endif
+}
+
+void
+_ecore_xcb_input_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+void
+#ifdef ECORE_XCB_XINPUT
+_ecore_xcb_input_handle_event(xcb_generic_event_t *event)
+#else
+_ecore_xcb_input_handle_event(xcb_generic_event_t * event EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XINPUT
+ xcb_ge_event_t *ev;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ /* FIXME: look at xlib ecore_x_xi2.c to copy logic in when i can find an
+ * xcb-input lib to test with */
+#ifdef ECORE_XCB_XINPUT
+ ev = (xcb_ge_event_t *)event;
+ switch (ev->event_type)
+ {
+ case XCB_INPUT_DEVICE_MOTION_NOTIFY:
+ {
+ xcb_input_device_motion_notify_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_motion_notify_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_move(de->time, de->state, de->event_x,
+ de->event_y, de->root_x, de->root_y,
+ de->event, child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ case XCB_INPUT_DEVICE_BUTTON_PRESS:
+ {
+ xcb_input_device_button_press_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_button_press_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ de->time, de->state, de->detail,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y, de->event,
+ child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ case XCB_INPUT_DEVICE_BUTTON_RELEASE:
+ {
+ xcb_input_device_button_release_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_button_release_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP,
+ de->time, de->state, de->detail,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y, de->event,
+ child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ case XCB_INPUT_DEVICE_TOUCH_UPDATE:
+ {
+ xcb_input_device_motion_notify_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_motion_notify_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_move(de->time, de->state, de->event_x,
+ de->event_y, de->root_x, de->root_y,
+ de->event, child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ case XCB_INPUT_DEVICE_TOUCH_BEGIN:
+ {
+ xcb_input_device_button_press_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_button_press_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ de->time, de->state, de->detail,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y, de->event,
+ child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ case XCB_INPUT_DEVICE_TOUCH_END:
+ {
+ xcb_input_device_button_release_event_t *de;
+ unsigned int child_win = 0;
+
+ de = (xcb_input_device_button_release_event_t *)ev->pad1;
+ child_win = (de->child ? de->child : de->event);
+ _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP,
+ de->time, de->state, de->detail,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y, de->event,
+ child_win, de->root,
+ de->same_screen, de->device_id,
+ 1, 1, 1.0, 0.0,
+ de->event_x, de->event_y,
+ de->root_x, de->root_y);
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_input_multi_select(Ecore_X_Window win)
+{
+ Eina_Bool find = EINA_FALSE;
+#ifdef ECORE_XCB_XINPUT
+ xcb_input_list_input_devices_cookie_t dcookie;
+ xcb_input_list_input_devices_reply_t *dreply;
+ xcb_input_device_info_iterator_t diter;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_input_avail) return EINA_FALSE;
+
+ /* FIXME: i can't seemingly test this! no xcb input lib so can't look and
+ * test and look at types etc. - look at xlib code and copy logic over
+ * when we can */
+#ifdef ECORE_XCB_XINPUT
+ dcookie = xcb_input_list_input_devices_unchecked(_ecore_xcb_conn);
+ dreply =
+ xcb_input_list_input_devices_reply(_ecore_xcb_conn, dcookie, NULL);
+ if (!dreply) return EINA_FALSE;
+
+ diter = xcb_input_list_input_devices_devices_iterator(dreply);
+ while (diter.rem)
+ {
+ xcb_input_device_info_t *dev;
+ const xcb_input_event_class_t iclass[] =
+ {
+ XCB_INPUT_DEVICE_BUTTON_PRESS,
+ XCB_INPUT_DEVICE_BUTTON_RELEASE,
+ XCB_INPUT_DEVICE_MOTION_NOTIFY,
+ XCB_INPUT_DEVICE_TOUCH_BEGIN,
+ XCB_INPUT_DEVICE_TOUCH_END,
+ XCB_INPUT_DEVICE_TOUCH_UPDATE
+ };
+
+ dev = diter.data;
+ if (dev->device_use == XCB_INPUT_DEVICE_USE_IS_X_EXTENSION_DEVICE)
+ {
+ DBG("Device %d", dev->device_id);
+ DBG("\tType: %d", dev->device_type);
+ DBG("\tNum Classes: %d", dev->num_class_info);
+ DBG("\tUse: %d", dev->device_use);
+
+ xcb_input_select_extension_event(_ecore_xcb_conn, win,
+ sizeof(iclass) / sizeof(xcb_input_event_class_t),
+ iclass);
+ find = EINA_TRUE;
+ }
+ xcb_input_device_info_next(&diter);
+ }
+ free(dreply);
+#endif
+
+ return find;
+ win = 0;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_keymap.c b/src/lib/ecore_x/xcb/ecore_xcb_keymap.c
new file mode 100644
index 0000000000..6c112464b0
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_keymap.c
@@ -0,0 +1,491 @@
+#include "ecore_xcb_private.h"
+#define NEED_KEYSYM_TABLE
+#define NEED_VTABLE
+#include "ecore_xcb_keysym_table.h"
+#include <xcb/xcb_keysyms.h>
+#include <X11/keysym.h>
+
+/* local function prototypes */
+static int _ecore_xcb_keymap_mask_get(void *reply,
+ xcb_keysym_t sym);
+static xcb_keysym_t _ecore_xcb_keymap_string_to_keysym(const char *str);
+static int _ecore_xcb_keymap_translate_key(xcb_keycode_t keycode,
+ unsigned int modifiers,
+ unsigned int *modifiers_return,
+ xcb_keysym_t *keysym_return);
+static int _ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym,
+ unsigned int modifiers,
+ char *buffer,
+ int bytes);
+
+/* local variables */
+static xcb_key_symbols_t *_ecore_xcb_keysyms;
+static int _ecore_xcb_mode_switch = 0;
+
+/* public variables */
+EAPI int ECORE_X_MODIFIER_SHIFT = 0;
+EAPI int ECORE_X_MODIFIER_CTRL = 0;
+EAPI int ECORE_X_MODIFIER_ALT = 0;
+EAPI int ECORE_X_MODIFIER_WIN = 0;
+EAPI int ECORE_X_MODIFIER_ALTGR = 0;
+EAPI int ECORE_X_LOCK_SCROLL = 0;
+EAPI int ECORE_X_LOCK_NUM = 0;
+EAPI int ECORE_X_LOCK_CAPS = 0;
+EAPI int ECORE_X_LOCK_SHIFT = 0;
+
+void
+_ecore_xcb_keymap_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_keysyms = xcb_key_symbols_alloc(_ecore_xcb_conn);
+}
+
+void
+_ecore_xcb_keymap_finalize(void)
+{
+ xcb_get_modifier_mapping_cookie_t cookie;
+ xcb_get_modifier_mapping_reply_t *reply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_modifier_mapping_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_modifier_mapping_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply)
+ {
+ xcb_key_symbols_free(_ecore_xcb_keysyms);
+ return;
+ }
+
+ _ecore_xcb_mode_switch = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch);
+
+ ECORE_X_MODIFIER_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_L);
+ ECORE_X_MODIFIER_CTRL = _ecore_xcb_keymap_mask_get(reply, XK_Control_L);
+
+ ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Alt_L);
+ if (!ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L);
+ if (!ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Super_L);
+
+ ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Super_L);
+ if (!ECORE_X_MODIFIER_WIN)
+ ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L);
+
+ ECORE_X_MODIFIER_ALTGR = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch);
+
+ if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_WIN = 0;
+ if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL)
+ ECORE_X_MODIFIER_ALT = 0;
+
+ ECORE_X_LOCK_SCROLL = _ecore_xcb_keymap_mask_get(reply, XK_Scroll_Lock);
+ ECORE_X_LOCK_NUM = _ecore_xcb_keymap_mask_get(reply, XK_Num_Lock);
+ ECORE_X_LOCK_CAPS = _ecore_xcb_keymap_mask_get(reply, XK_Caps_Lock);
+ ECORE_X_LOCK_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_Lock);
+}
+
+void
+_ecore_xcb_modifiers_get(void)
+{
+ _ecore_xcb_keymap_finalize();
+}
+
+void
+_ecore_xcb_keymap_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (_ecore_xcb_keysyms) xcb_key_symbols_free(_ecore_xcb_keysyms);
+}
+
+void
+_ecore_xcb_keymap_refresh(xcb_mapping_notify_event_t *event)
+{
+ CHECK_XCB_CONN;
+ xcb_refresh_keyboard_mapping(_ecore_xcb_keysyms, event);
+}
+
+xcb_keysym_t
+_ecore_xcb_keymap_keycode_to_keysym(xcb_keycode_t keycode,
+ int col)
+{
+ xcb_keysym_t key0, key1;
+
+ CHECK_XCB_CONN;
+ if (col & _ecore_xcb_mode_switch)
+ {
+ key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 4);
+ key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 5);
+ }
+ else
+ {
+ key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 0);
+ key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 1);
+ }
+
+ if (key1 == XCB_NO_SYMBOL)
+ key1 = key0;
+
+ if ((col & ECORE_X_LOCK_NUM) &&
+ ((xcb_is_keypad_key(key1)) || (xcb_is_private_keypad_key(key1))))
+ {
+ if ((col & XCB_MOD_MASK_SHIFT) ||
+ ((col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_SHIFT)))
+ return key0;
+ else
+ return key1;
+ }
+ else if (!(col & XCB_MOD_MASK_SHIFT) && !(col & XCB_MOD_MASK_LOCK))
+ return key0;
+ else if (!(col & XCB_MOD_MASK_SHIFT) &&
+ (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_CAPS)))
+ return key1;
+ else if ((col & XCB_MOD_MASK_SHIFT) &&
+ (col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_CAPS))
+ return key0;
+ else if ((col & XCB_MOD_MASK_SHIFT) ||
+ (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_SHIFT)))
+ return key1;
+
+ return XCB_NO_SYMBOL;
+}
+
+xcb_keycode_t *
+_ecore_xcb_keymap_keysym_to_keycode(xcb_keysym_t keysym)
+{
+ CHECK_XCB_CONN;
+ return xcb_key_symbols_get_keycode(_ecore_xcb_keysyms, keysym);
+}
+
+char *
+_ecore_xcb_keymap_keysym_to_string(xcb_keysym_t keysym)
+{
+ int i = 0, n = 0, h = 0, idx = 0;
+ const unsigned char *entry;
+ unsigned char val1, val2, val3, val4;
+
+ CHECK_XCB_CONN;
+ if (!keysym) return NULL;
+ if (keysym == XK_VoidSymbol) keysym = 0;
+ if (keysym <= 0x1fffffff)
+ {
+ val1 = (keysym >> 24);
+ val2 = ((keysym >> 16) & 0xff);
+ val3 = ((keysym >> 8) & 0xff);
+ val4 = (keysym & 0xff);
+ i = keysym % VTABLESIZE;
+ h = i + 1;
+ n = VMAXHASH;
+ while ((idx = hashKeysym[i]))
+ {
+ entry = &_ecore_xcb_keytable[idx];
+ if ((entry[0] == val1) && (entry[1] == val2) &&
+ (entry[2] == val3) && (entry[3] == val4))
+ return (char *)entry + 4;
+ if (!--n) break;
+ i += h;
+ if (i >= VTABLESIZE) i -= VTABLESIZE;
+ }
+ }
+
+ if ((keysym >= 0x01000100) && (keysym <= 0x0110ffff))
+ {
+ xcb_keysym_t val;
+ char *s = NULL;
+ int i = 0;
+
+ val = (keysym & 0xffffff);
+ if (val & 0xff0000)
+ i = 10;
+ else
+ i = 6;
+
+ if (!(s = malloc(i))) return NULL;
+ i--;
+ s[i--] = '\0';
+ for (; i; i--)
+ {
+ val1 = (val & 0xf);
+ val >>= 4;
+ if (val1 < 10)
+ s[i] = '0' + val1;
+ else
+ s[i] = 'A' + val1 - 10;
+ }
+ s[i] = 'U';
+ return s;
+ }
+
+ return NULL;
+}
+
+xcb_keycode_t
+_ecore_xcb_keymap_string_to_keycode(const char *key)
+{
+ if (!strncmp(key, "Keycode-", 8))
+ return atoi(key + 8);
+ else
+ {
+ xcb_keysym_t keysym = XCB_NO_SYMBOL;
+ xcb_keycode_t *keycodes, keycode = 0;
+ int i = 0;
+
+ CHECK_XCB_CONN;
+
+ keysym = _ecore_xcb_keymap_string_to_keysym(key);
+ if (keysym == XCB_NO_SYMBOL) return XCB_NO_SYMBOL;
+
+ keycodes = _ecore_xcb_keymap_keysym_to_keycode(keysym);
+ if (!keycodes) return XCB_NO_SYMBOL;
+
+ while (keycodes[i] != XCB_NO_SYMBOL)
+ {
+ if (keycodes[i] != 0)
+ {
+ keycode = keycodes[i];
+ break;
+ }
+ i++;
+ }
+ return keycode;
+ }
+}
+
+int
+_ecore_xcb_keymap_lookup_string(xcb_keycode_t keycode,
+ int state,
+ char *buffer,
+ int bytes,
+ xcb_keysym_t *sym)
+{
+ unsigned int modifiers = 0;
+ xcb_keysym_t keysym;
+
+ CHECK_XCB_CONN;
+ if (!_ecore_xcb_keymap_translate_key(keycode, state, &modifiers, &keysym))
+ return 0;
+
+ if (sym) *sym = keysym;
+
+ return _ecore_xcb_keymap_translate_keysym(keysym, state, buffer, bytes);
+}
+
+EAPI const char *
+ecore_x_keysym_string_get(int keysym)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_keymap_keysym_to_string(keysym);
+}
+
+EAPI int
+ecore_x_keysym_keycode_get(const char *keyname)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_keymap_string_to_keycode(keyname);
+}
+
+/* local functions */
+static int
+_ecore_xcb_keymap_mask_get(void *reply,
+ xcb_keysym_t sym)
+{
+ xcb_get_modifier_mapping_reply_t *rep;
+ xcb_keysym_t sym2;
+ int mask = 0;
+ const int masks[8] =
+ {
+ XCB_MOD_MASK_SHIFT, XCB_MOD_MASK_LOCK, XCB_MOD_MASK_CONTROL,
+ XCB_MOD_MASK_1, XCB_MOD_MASK_2, XCB_MOD_MASK_3, XCB_MOD_MASK_4,
+ XCB_MOD_MASK_5
+ };
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ rep = (xcb_get_modifier_mapping_reply_t *)reply;
+ if ((rep) && (rep->keycodes_per_modifier > 0))
+ {
+ int i = 0;
+ xcb_keycode_t *modmap;
+
+ modmap = xcb_get_modifier_mapping_keycodes(rep);
+ for (i = 0; i < (8 * rep->keycodes_per_modifier); i++)
+ {
+ int j = 0;
+
+ for (j = 0; j < 8; j++)
+ {
+ sym2 =
+ xcb_key_symbols_get_keysym(_ecore_xcb_keysyms,
+ modmap[i], j);
+ if (sym2 != 0) break;
+ }
+ if (sym2 == sym)
+ {
+ mask = masks[i / rep->keycodes_per_modifier];
+ break;
+ }
+ }
+ }
+
+ return mask;
+}
+
+static xcb_keysym_t
+_ecore_xcb_keymap_string_to_keysym(const char *str)
+{
+ int i = 0, n = 0, h = 0;
+ unsigned long sig = 0;
+ const char *p = NULL;
+ int c = 0, idx = 0;
+ const unsigned char *entry;
+ unsigned char sig1, sig2;
+ long unsigned int val;
+
+ p = str;
+ while ((c = *p++))
+ sig = (sig << 1) + c;
+
+ i = (sig % KTABLESIZE);
+ h = i + 1;
+ sig1 = (sig >> 8) & 0xff;
+ sig2 = sig & 0xff;
+ n = KMAXHASH;
+
+ while ((idx = hashString[i]))
+ {
+ entry = &_ecore_xcb_keytable[idx];
+ if ((entry[0] == sig1) && (entry[1] == sig2) &&
+ !strcmp(str, (char *)entry + 6))
+ {
+ val = ((entry[2] << 24) | (entry[3] << 16) |
+ (entry[4] << 8) | (entry[5]));
+ if (!val) val = 0xffffff;
+ return val;
+ }
+ if (!--n) break;
+ i += h;
+ if (i >= KTABLESIZE) i -= KTABLESIZE;
+ }
+
+ if (*str == 'U')
+ {
+ val = 0;
+ for (p = &str[1]; *p; p++)
+ {
+ c = *p;
+ if (('0' <= c) && (c <= '9'))
+ val = (val << 4) + c - '0';
+ else if (('a' <= c) && (c <= 'f'))
+ val = (val << 4) + c - 'a' + 10;
+ else if (('A' <= c) && (c <= 'F'))
+ val = (val << 4) + c - 'A' + 10;
+ else
+ return XCB_NO_SYMBOL;
+ if (val > 0x10ffff) return XCB_NO_SYMBOL;
+ }
+ if ((val < 0x20) || ((val > 0x7e) && (val < 0xa0)))
+ return XCB_NO_SYMBOL;
+ if (val < 0x100) return val;
+ return val | 0x01000000;
+ }
+
+ if ((strlen(str) > 2) && (str[0] == '0') && (str[1] == 'x'))
+ {
+ char *tmp = NULL;
+
+ val = strtoul(str, &tmp, 16);
+ if ((val == ULONG_MAX) || ((tmp) && (*tmp != '\0')))
+ return XCB_NO_SYMBOL;
+ else
+ return val;
+ }
+
+ if (!strncmp(str, "XF86_", 5))
+ {
+ long unsigned int ret;
+ char *tmp;
+
+ tmp = strdup(str);
+ if (!tmp) return XCB_NO_SYMBOL;
+ memmove(&tmp[4], &tmp[5], strlen(str) - 5 + 1);
+ ret = _ecore_xcb_keymap_string_to_keysym(tmp);
+ free(tmp);
+ return ret;
+ }
+
+ return XCB_NO_SYMBOL;
+}
+
+static int
+_ecore_xcb_keymap_translate_key(xcb_keycode_t keycode,
+ unsigned int modifiers,
+ unsigned int *modifiers_return,
+ xcb_keysym_t *keysym_return)
+{
+ xcb_keysym_t sym;
+
+ if (!_ecore_xcb_keysyms) return 0;
+
+ sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, modifiers);
+
+ if (modifiers_return)
+ *modifiers_return = ((XCB_MOD_MASK_SHIFT | XCB_MOD_MASK_LOCK) |
+ _ecore_xcb_mode_switch | ECORE_X_LOCK_NUM);
+ if (keysym_return)
+ *keysym_return = sym;
+
+ return 1;
+}
+
+static int
+_ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym,
+ unsigned int modifiers,
+ char *buffer,
+ int bytes)
+{
+ unsigned long hbytes = 0;
+ unsigned char c;
+
+ if (!keysym) return 0;
+ hbytes = (keysym >> 8);
+
+ if (!(bytes &&
+ ((hbytes == 0) ||
+ ((hbytes == 0xFF) &&
+ (((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
+ (keysym == XK_Return) || (keysym == XK_Escape) ||
+ (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
+ (keysym == XK_KP_Enter) ||
+ ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
+ (keysym == XK_KP_Equal) || (keysym == XK_Delete))))))
+ return 0;
+
+ if (keysym == XK_KP_Space)
+ c = (XK_space & 0x7F);
+ else if (hbytes == 0xFF)
+ c = (keysym & 0x7F);
+ else
+ c = (keysym & 0xFF);
+
+ if (modifiers & ECORE_X_MODIFIER_CTRL)
+ {
+ if (((c >= '@') && (c < '\177')) || c == ' ')
+ c &= 0x1F;
+ else if (c == '2')
+ c = '\000';
+ else if ((c >= '3') && (c <= '7'))
+ c -= ('3' - '\033');
+ else if (c == '8')
+ c = '\177';
+ else if (c == '/')
+ c = '_' & 0x1F;
+ }
+ buffer[0] = c;
+ return 1;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_mwm.c b/src/lib/ecore_x/xcb/ecore_xcb_mwm.c
new file mode 100644
index 0000000000..6c9533136f
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_mwm.c
@@ -0,0 +1,104 @@
+#include "ecore_xcb_private.h"
+//#include "Ecore_X_Atoms.h"
+
+#define ECORE_X_MWM_HINTS_FUNCTIONS (1 << 0)
+#define ECORE_X_MWM_HINTS_DECORATIONS (1 << 1)
+#define ECORE_X_MWM_HINTS_INPUT_MODE (1 << 2)
+#define ECORE_X_MWM_HINTS_STATUS (1 << 3)
+
+typedef struct _mwmhints
+{
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t inputmode;
+ uint32_t status;
+} MWMHints;
+
+/**
+ * @defgroup Ecore_X_MWM_Group MWM related functions.
+ *
+ * Functions related to MWM.
+ */
+
+/**
+ * Sets the borderless flag of a window using MWM.
+ *
+ * @param win The window.
+ * @param borderless The borderless flag.
+ *
+ * @ingroup Ecore_X_MWM_Group
+ */
+EAPI void
+ecore_x_mwm_borderless_set(Ecore_X_Window win,
+ Eina_Bool borderless)
+{
+ uint32_t data[5] = { 0, 0, 0, 0, 0 };
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ data[0] = 2;
+ data[2] = !borderless;
+
+ ecore_x_window_prop_property_set(win,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ ECORE_X_ATOM_MOTIF_WM_HINTS, 32,
+ (void *)data, 5);
+}
+
+EAPI Eina_Bool
+ecore_x_mwm_hints_get(Ecore_X_Window win,
+ Ecore_X_MWM_Hint_Func *fhint,
+ Ecore_X_MWM_Hint_Decor *dhint,
+ Ecore_X_MWM_Hint_Input *ihint)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ MWMHints *mwmhints = NULL;
+ int ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie =
+ xcb_get_property_unchecked(_ecore_xcb_conn, 0, win,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ ECORE_X_ATOM_MOTIF_WM_HINTS, 0, UINT_MAX);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+ if ((reply->format != 32) || (reply->value_len == 0))
+ {
+ free(reply);
+ return EINA_FALSE;
+ }
+
+ mwmhints = xcb_get_property_value(reply);
+ if (reply->value_len >= 4)
+ {
+ if (dhint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_DECORATIONS)
+ *dhint = mwmhints->decorations;
+ else
+ *dhint = ECORE_X_MWM_HINT_DECOR_ALL;
+ }
+ if (fhint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_FUNCTIONS)
+ *fhint = mwmhints->functions;
+ else
+ *fhint = ECORE_X_MWM_HINT_FUNC_ALL;
+ }
+ if (ihint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_INPUT_MODE)
+ *ihint = mwmhints->inputmode;
+ else
+ *ihint = ECORE_X_MWM_HINT_INPUT_MODELESS;
+ }
+ ret = EINA_TRUE;
+ }
+ free(reply);
+ return ret;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_netwm.c b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c
new file mode 100644
index 0000000000..ae801d3407
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c
@@ -0,0 +1,1604 @@
+#include "ecore_xcb_private.h"
+
+/* local function prototypes */
+/* static void _ecore_xcb_netwm_startup_info_free(void *data); */
+static Ecore_X_Atom _ecore_xcb_netwm_window_type_atom_get(Ecore_X_Window_Type type);
+static Ecore_X_Window_Type _ecore_xcb_netwm_window_type_type_get(Ecore_X_Atom atom);
+static Ecore_X_Atom _ecore_xcb_netwm_window_state_atom_get(Ecore_X_Window_State state);
+static Ecore_X_Atom _ecore_xcb_netwm_action_atom_get(Ecore_X_Action action);
+
+/* local variables */
+//static Eina_Hash *_startup_info = NULL;
+
+/* local structures */
+typedef struct _Ecore_Xcb_Startup_Info Ecore_Xcb_Startup_Info;
+struct _Ecore_Xcb_Startup_Info
+{
+ Ecore_X_Window win;
+ int init, size;
+ char *buffer;
+ int length;
+
+ /* sequence info fields */
+ char *id, *name;
+ int screen;
+ char *bin, *icon;
+ int desktop, timestamp;
+ char *description, *wmclass;
+ int silent;
+};
+
+EAPI void
+ecore_x_netwm_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+// _startup_info =
+// eina_hash_string_superfast_new(_ecore_xcb_netwm_startup_info_free);
+}
+
+EAPI void
+ecore_x_netwm_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+// if (_startup_info) eina_hash_free(_startup_info);
+// _startup_info = NULL;
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_pid_get(Ecore_X_Window win,
+ int *pid)
+{
+ uint32_t tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_PID, &tmp, 1))
+ return EINA_FALSE;
+
+ if (pid) *pid = tmp;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_pid_set(Ecore_X_Window win,
+ int pid)
+{
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ tmp = pid;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_PID, &tmp, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_window_type_get(Ecore_X_Window win,
+ Ecore_X_Window_Type *type)
+{
+ Ecore_X_Atom *atoms;
+ int num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (type) *type = ECORE_X_WINDOW_TYPE_NORMAL;
+
+ num =
+ ecore_x_window_prop_atom_list_get(win,
+ ECORE_X_ATOM_NET_WM_WINDOW_TYPE, &atoms);
+ if ((type) && (num >= 1) && (atoms))
+ *type = _ecore_xcb_netwm_window_type_type_get(atoms[0]);
+
+ if (atoms) free(atoms);
+
+ if (num >= 1) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_netwm_window_type_set(Ecore_X_Window win,
+ Ecore_X_Window_Type type)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ atom = _ecore_xcb_netwm_window_type_atom_get(type);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, &atom, 1);
+}
+
+EAPI int
+ecore_x_netwm_window_types_get(Ecore_X_Window win,
+ Ecore_X_Window_Type **types)
+{
+ int num = 0, i = 0;
+ Ecore_X_Atom *atoms = NULL;
+ Ecore_X_Window_Type *atoms2 = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (types) *types = NULL;
+ num =
+ ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atoms);
+ if ((num <= 0) || (!atoms))
+ {
+ if (atoms) free(atoms);
+ return 0;
+ }
+
+ atoms2 = malloc(num * sizeof(Ecore_X_Window_Type));
+ if (!atoms2)
+ {
+ if (atoms) free(atoms);
+ return 0;
+ }
+
+ for (i = 0; i < num; i++)
+ atoms2[i] = _ecore_xcb_netwm_window_type_type_get(atoms[i]);
+ if (atoms) free(atoms);
+
+ if (types)
+ *types = atoms2;
+ else
+ free(atoms2);
+
+ return num;
+}
+
+EAPI int
+ecore_x_netwm_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (name)
+ *name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_WM_NAME);
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_NAME, name);
+}
+
+EAPI void
+ecore_x_netwm_opacity_set(Ecore_X_Window win,
+ unsigned int opacity)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
+ &opacity, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_opacity_get(Ecore_X_Window win,
+ unsigned int *opacity)
+{
+ unsigned int tmp = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
+ &tmp, 1))
+ return EINA_FALSE;
+
+ if (opacity) *opacity = tmp;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_wm_identify(Ecore_X_Window root,
+ Ecore_X_Window check,
+ const char *wm_name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(check, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
+ &check, 1);
+ ecore_x_window_prop_string_set(check, ECORE_X_ATOM_NET_WM_NAME, wm_name);
+ ecore_x_window_prop_string_set(root, ECORE_X_ATOM_NET_WM_NAME, wm_name);
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
+ &check, 1);
+}
+
+EAPI void
+ecore_x_netwm_supported_set(Ecore_X_Window root,
+ Ecore_X_Atom *supported,
+ int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED,
+ supported, num);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_supported_get(Ecore_X_Window root,
+ Ecore_X_Atom **supported,
+ int *num)
+{
+ int num_ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (num) *num = 0;
+ if (supported) *supported = NULL;
+
+ num_ret =
+ ecore_x_window_prop_atom_list_get(root, ECORE_X_ATOM_NET_SUPPORTED,
+ supported);
+ if (num_ret <= 0) return EINA_FALSE;
+ if (num) *num = num_ret;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_desk_count_set(Ecore_X_Window root,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS,
+ &n_desks, 1);
+}
+
+EAPI void
+ecore_x_netwm_desk_roots_set(Ecore_X_Window root,
+ Ecore_X_Window *vroots,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_VIRTUAL_ROOTS,
+ vroots, n_desks);
+}
+
+EAPI void
+ecore_x_netwm_desk_names_set(Ecore_X_Window root,
+ const char **names,
+ unsigned int n_desks)
+{
+ char ss[32], *buf = NULL, *t = NULL;
+ const char *s;
+ uint32_t len = 0, i, l;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ for (i = 0; i < n_desks; i++)
+ {
+ s = ((names) ? names[i] : NULL);
+ if (!s)
+ {
+ /* Default to "Desk-<number>" */
+ sprintf(ss, "Desk-%d", i);
+ s = ss;
+ }
+
+ l = strlen(s) + 1;
+ t = realloc(buf, len + 1);
+ if (t)
+ {
+ buf = t;
+ memcpy(buf + len, s, l);
+ }
+ len += l;
+ }
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, root,
+ ECORE_X_ATOM_NET_DESKTOP_NAMES,
+ ECORE_X_ATOM_UTF8_STRING, 8, len, (const void *)buf);
+// ecore_x_flush();
+ free(buf);
+}
+
+EAPI void
+ecore_x_netwm_desk_size_set(Ecore_X_Window root,
+ unsigned int width,
+ unsigned int height)
+{
+ uint32_t size[2];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ size[0] = width;
+ size[1] = height;
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_GEOMETRY,
+ size, 2);
+}
+
+EAPI void
+ecore_x_netwm_desk_viewports_set(Ecore_X_Window root,
+ unsigned int *origins,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_VIEWPORT,
+ origins, (2 * n_desks));
+}
+
+EAPI void
+ecore_x_netwm_desk_layout_set(Ecore_X_Window root,
+ int orientation,
+ int columns,
+ int rows,
+ int starting_corner)
+{
+ unsigned int layout[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ layout[0] = orientation;
+ layout[1] = columns;
+ layout[2] = rows;
+ layout[3] = starting_corner;
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_LAYOUT,
+ layout, 4);
+}
+
+EAPI void
+ecore_x_netwm_desk_workareas_set(Ecore_X_Window root,
+ unsigned int *areas,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_WORKAREA, areas,
+ 4 * n_desks);
+}
+
+EAPI unsigned int *
+ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks)
+{
+ int ret;
+ unsigned int *areas = NULL;
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ ret = ecore_x_window_prop_card32_list_get(root, ECORE_X_ATOM_NET_WORKAREA,
+ &areas);
+ if (!areas)
+ {
+ if (n_desks) *n_desks = 0;
+ return 0;
+ }
+ if (n_desks) *n_desks = ret / 4;
+ return areas;
+}
+
+EAPI void
+ecore_x_netwm_desk_current_set(Ecore_X_Window root,
+ unsigned int desk)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_CURRENT_DESKTOP,
+ &desk, 1);
+}
+
+EAPI void
+ecore_x_netwm_showing_desktop_set(Ecore_X_Window root,
+ Eina_Bool on)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ val = ((on) ? 1 : 0);
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_SHOWING_DESKTOP,
+ &val, 1);
+}
+
+EAPI int
+ecore_x_netwm_startup_id_get(Ecore_X_Window win,
+ char **id)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (id)
+ {
+ *id =
+ ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_STARTUP_ID);
+ }
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_startup_id_set(Ecore_X_Window win,
+ const char *id)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_STARTUP_ID, id);
+}
+
+EAPI void
+ecore_x_netwm_state_request_send(Ecore_X_Window win,
+ Ecore_X_Window root,
+ Ecore_X_Window_State s1,
+ Ecore_X_Window_State s2,
+ Eina_Bool set)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_NET_WM_STATE;
+ ev.data.data32[0] = !!set;
+ ev.data.data32[1] = _ecore_xcb_netwm_window_state_atom_get(s1);
+ ev.data.data32[2] = _ecore_xcb_netwm_window_state_atom_get(s2);
+ /* 1 == normal client, if used in a pager this should be 2 */
+ ev.data.data32[3] = 1;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_netwm_window_state_set(Ecore_X_Window win,
+ Ecore_X_Window_State *state,
+ unsigned int num)
+{
+ Ecore_X_Atom *set;
+ unsigned int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!num)
+ {
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_NET_WM_STATE);
+ return;
+ }
+
+ set = malloc(num * sizeof(Ecore_X_Atom));
+ if (!set) return;
+
+ for (i = 0; i < num; i++)
+ set[i] = _ecore_xcb_netwm_window_state_atom_get(state[i]);
+
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_STATE, set, num);
+ free(set);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_window_state_get(Ecore_X_Window win,
+ Ecore_X_Window_State **state,
+ unsigned int *num)
+{
+ Ecore_X_Atom *atoms;
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (num) *num = 0;
+ if (state) *state = NULL;
+
+ ret =
+ ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_STATE, &atoms);
+
+ if (ret <= 0) return EINA_FALSE;
+
+ if (state)
+ {
+ *state = malloc(ret * sizeof(Ecore_X_Window_State));
+ if (*state)
+ {
+ int i = 0;
+
+ for (i = 0; i < ret; i++)
+ (*state)[i] = _ecore_xcb_netwm_window_state_get(atoms[i]);
+ if (num) *num = ret;
+ }
+ }
+
+ free(atoms);
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_client_active_set(Ecore_X_Window root,
+ Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(root,
+ ECORE_X_ATOM_NET_ACTIVE_WINDOW, &win, 1);
+}
+
+EAPI void
+ecore_x_netwm_client_active_request(Ecore_X_Window root,
+ Ecore_X_Window win,
+ int type,
+ Ecore_X_Window current_win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_NET_ACTIVE_WINDOW;
+ ev.data.data32[0] = type;
+ ev.data.data32[1] = XCB_CURRENT_TIME;
+ ev.data.data32[2] = current_win;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_netwm_client_list_set(Ecore_X_Window root,
+ Ecore_X_Window *p_clients,
+ unsigned int n_clients)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST,
+ p_clients, n_clients);
+}
+
+EAPI void
+ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root,
+ Ecore_X_Window *p_clients,
+ unsigned int n_clients)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST_STACKING,
+ p_clients, n_clients);
+}
+
+EAPI Eina_Bool
+ecore_x_screen_is_composited(int screen)
+{
+ char buff[32];
+ xcb_get_selection_owner_cookie_t ocookie;
+ xcb_get_selection_owner_reply_t *oreply;
+ Ecore_X_Window win;
+ static Ecore_X_Atom atom = XCB_NONE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ snprintf(buff, sizeof(buff), "_NET_WM_CM_S%i", screen);
+
+ if (atom == XCB_NONE)
+ {
+ xcb_intern_atom_cookie_t acookie;
+ xcb_intern_atom_reply_t *areply;
+
+ acookie =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(buff), buff);
+ areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL);
+ if (!areply) return EINA_FALSE;
+ atom = areply->atom;
+ free(areply);
+ }
+ if (atom == XCB_NONE) return EINA_FALSE;
+
+ ocookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, atom);
+ oreply = xcb_get_selection_owner_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (!oreply) return EINA_FALSE;
+ win = oreply->owner;
+ free(oreply);
+
+ return (win != XCB_NONE) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_screen_is_composited_set(int screen,
+ Ecore_X_Window win)
+{
+ static Ecore_X_Atom atom = XCB_NONE;
+ char buff[32];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ snprintf(buff, sizeof(buff), "_NET_WM_CM_S%i", screen);
+ if (atom == XCB_NONE)
+ {
+ xcb_intern_atom_cookie_t acookie;
+ xcb_intern_atom_reply_t *areply;
+
+ acookie =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(buff), buff);
+ areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL);
+ if (!areply) return;
+ atom = areply->atom;
+ free(areply);
+ }
+ if (atom == XCB_NONE) return;
+ xcb_set_selection_owner(_ecore_xcb_conn, win, atom,
+ _ecore_xcb_events_last_time_get());
+}
+
+EAPI void
+ecore_x_netwm_ping_send(Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_WM_PROTOCOLS;
+ ev.data.data32[0] = ECORE_X_ATOM_NET_WM_PING;
+ ev.data.data32[1] = ecore_x_current_time_get();
+ ev.data.data32[2] = win;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_netwm_frame_size_set(Ecore_X_Window win,
+ int fl,
+ int fr,
+ int ft,
+ int fb)
+{
+ uint32_t frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ frames[0] = fl;
+ frames[1] = fr;
+ frames[2] = ft;
+ frames[3] = fb;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_FRAME_EXTENTS,
+ frames, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_frame_size_get(Ecore_X_Window win,
+ int *fl,
+ int *fr,
+ int *ft,
+ int *fb)
+{
+ int ret = 0;
+ unsigned int frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_FRAME_EXTENTS,
+ frames, 4);
+ if (ret != 4) return EINA_FALSE;
+
+ if (fl) *fl = frames[0];
+ if (fr) *fr = frames[1];
+ if (ft) *ft = frames[2];
+ if (fb) *fb = frames[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_sync_request_send(Ecore_X_Window win,
+ unsigned int serial)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ /* FIXME: Maybe need XSyncIntToValue ?? */
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_WM_PROTOCOLS;
+ ev.data.data32[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+ ev.data.data32[1] = _ecore_xcb_events_last_time_get();
+ ev.data.data32[2] = serial;
+ ev.data.data32[3] = 0;
+ ev.data.data32[4] = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_netwm_desktop_set(Ecore_X_Window win,
+ unsigned int desk)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_desktop_get(Ecore_X_Window win,
+ unsigned int *desk)
+{
+ unsigned int tmp = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_DESKTOP,
+ &tmp, 1))
+ return EINA_FALSE;
+
+ if (desk) *desk = tmp;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_desktop_request_send(Ecore_X_Window win,
+ Ecore_X_Window root,
+ unsigned int desktop)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_NET_WM_DESKTOP;
+ ev.data.data32[0] = desktop;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_netwm_moveresize_request_send(Ecore_X_Window win,
+ int x,
+ int y,
+ Ecore_X_Netwm_Direction direction,
+ unsigned int button)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = ECORE_X_ATOM_NET_WM_MOVERESIZE;
+ ev.data.data32[0] = x;
+ ev.data.data32[1] = y;
+ ev.data.data32[2] = direction;
+ ev.data.data32[3] = button;
+ ev.data.data32[4] = 1;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev);
+}
+
+EAPI void
+ecore_x_netwm_handled_icons_set(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
+ NULL, 0);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_handled_icons_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
+ NULL, 0))
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+EAPI int
+ecore_x_netwm_icon_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (name)
+ {
+ *name =
+ ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_WM_ICON_NAME);
+ }
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_icon_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_ICON_NAME, name);
+}
+
+EAPI void
+ecore_x_netwm_icons_set(Ecore_X_Window win,
+ Ecore_X_Icon *icon,
+ int num)
+{
+ unsigned int *data, *p, *p2;
+ unsigned int i, size, x, y;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ size = 0;
+ for (i = 0; i < (unsigned int)num; i++)
+ {
+ size += 2 + (icon[i].width * icon[i].height);
+ }
+ data = malloc(size * sizeof(unsigned int));
+ if (!data) return;
+ p = data;
+ for (i = 0; i < (unsigned int)num; i++)
+ {
+ p[0] = icon[i].width;
+ p[1] = icon[i].height;
+ p += 2;
+ p2 = icon[i].data;
+ for (y = 0; y < icon[i].height; y++)
+ {
+ for (x = 0; x < icon[i].width; x++)
+ {
+ unsigned int r, g, b, a;
+
+ a = (*p2 >> 24) & 0xff;
+ r = (*p2 >> 16) & 0xff;
+ g = (*p2 >> 8 ) & 0xff;
+ b = (*p2 ) & 0xff;
+ if ((a > 0) && (a < 255))
+ {
+ r = (r * 255) / a;
+ g = (g * 255) / a;
+ b = (b * 255) / a;
+ }
+ *p = (a << 24) | (r << 16) | (g << 8) | b;
+ p++;
+ p2++;
+ }
+ }
+ }
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON,
+ data, size);
+ free(data);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_icons_get(Ecore_X_Window win,
+ Ecore_X_Icon **icon,
+ int *num)
+{
+ int num_ret = 0;
+ unsigned int i = 0, len = 0, icons = 0;
+ unsigned int *data, *p, *src;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (num) *num = 0;
+ if (icon) *icon = NULL;
+
+ num_ret =
+ ecore_x_window_prop_card32_list_get(win, ECORE_X_ATOM_NET_WM_ICON, &data);
+
+ if ((num_ret <= 0) || (!data))
+ {
+ if (data) free(data);
+ return EINA_FALSE;
+ }
+ if (num_ret < 2)
+ {
+ if (data) free(data);
+ return EINA_FALSE;
+ }
+
+ icons = 0;
+ p = data;
+ while (p)
+ {
+ len = (p[0] * p[1]);
+ p += (len + 2);
+ if ((p - data) > num_ret)
+ {
+ if (data) free(data);
+ return EINA_FALSE;
+ }
+ icons++;
+ if ((p - data) == num_ret) p = NULL;
+ }
+ if (num) *num = icons;
+ if (!icon)
+ {
+ if (data) free(data);
+ return EINA_TRUE;
+ }
+
+ *icon = malloc(icons * sizeof(Ecore_X_Icon));
+ if (!(*icon))
+ {
+ if (data) free(data);
+ return EINA_FALSE;
+ }
+
+ /* Fetch the icons */
+ p = data;
+ for (i = 0; i < icons; i++)
+ {
+ unsigned int *ps, *pd, *pe;
+
+ len = p[0] * p[1];
+ ((*icon)[i]).width = p[0];
+ ((*icon)[i]).height = p[1];
+ src = &(p[2]);
+ ((*icon)[i]).data = malloc(len * sizeof(unsigned int));
+ if (!((*icon)[i]).data)
+ {
+ while (i)
+ free(((*icon)[--i]).data);
+ free(*icon);
+ free(data);
+ return EINA_FALSE;
+ }
+
+ pd = ((*icon)[i]).data;
+ ps = src;
+ pe = ps + len;
+ for (; ps < pe; ps++)
+ {
+ unsigned int r, g, b, a;
+
+ a = (*ps >> 24) & 0xff;
+ r = (((*ps >> 16) & 0xff) * a) / 255;
+ g = (((*ps >> 8) & 0xff) * a) / 255;
+ b = (((*ps) & 0xff) * a) / 255;
+ *pd = (a << 24) | (r << 16) | (g << 8) | (b);
+ pd++;
+ }
+ p += (len + 2);
+ }
+
+ if (data) free(data);
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_icon_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_icon_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret =
+ ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY,
+ geom, 4);
+ if (ret != 4) return EINA_FALSE;
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_strut_set(Ecore_X_Window win,
+ int l,
+ int r,
+ int t,
+ int b)
+{
+ unsigned int strut[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ strut[0] = l;
+ strut[1] = r;
+ strut[2] = t;
+ strut[3] = b;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_strut_get(Ecore_X_Window win,
+ int *l,
+ int *r,
+ int *t,
+ int *b)
+{
+ unsigned int strut[4];
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret =
+ ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4);
+ if (ret != 4) return EINA_FALSE;
+
+ if (l) *l = strut[0];
+ if (r) *r = strut[1];
+ if (t) *t = strut[2];
+ if (b) *b = strut[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_strut_partial_set(Ecore_X_Window win,
+ int left,
+ int right,
+ int top,
+ int bottom,
+ int left_start_y,
+ int left_end_y,
+ int right_start_y,
+ int right_end_y,
+ int top_start_x,
+ int top_end_x,
+ int bottom_start_x,
+ int bottom_end_x)
+{
+ unsigned int strut[12];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ strut[0] = left;
+ strut[1] = right;
+ strut[2] = top;
+ strut[3] = bottom;
+ strut[4] = left_start_y;
+ strut[5] = left_end_y;
+ strut[6] = right_start_y;
+ strut[7] = right_end_y;
+ strut[8] = top_start_x;
+ strut[9] = top_end_x;
+ strut[10] = bottom_start_x;
+ strut[11] = bottom_end_x;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL,
+ strut, 12);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_strut_partial_get(Ecore_X_Window win,
+ int *left,
+ int *right,
+ int *top,
+ int *bottom,
+ int *left_start_y,
+ int *left_end_y,
+ int *right_start_y,
+ int *right_end_y,
+ int *top_start_x,
+ int *top_end_x,
+ int *bottom_start_x,
+ int *bottom_end_x)
+{
+ unsigned int strut[12];
+ int ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ret =
+ ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL,
+ strut, 12);
+ if (ret != 12) return EINA_FALSE;
+
+ if (left) *left = strut[0];
+ if (right) *right = strut[1];
+ if (top) *top = strut[2];
+ if (bottom) *bottom = strut[3];
+ if (left_start_y) *left_start_y = strut[4];
+ if (left_end_y) *left_end_y = strut[5];
+ if (right_start_y) *right_start_y = strut[6];
+ if (right_end_y) *right_end_y = strut[7];
+ if (top_start_x) *top_start_x = strut[8];
+ if (top_end_x) *top_end_x = strut[9];
+ if (bottom_start_x) *bottom_start_x = strut[10];
+ if (bottom_end_x) *bottom_end_x = strut[11];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_user_time_set(Ecore_X_Window win,
+ unsigned int t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_USER_TIME, &t, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_user_time_get(Ecore_X_Window win,
+ unsigned int *t)
+{
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_USER_TIME,
+ &tmp, 1))
+ return EINA_FALSE;
+
+ if (t) *t = tmp;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_visible_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_NAME,
+ name);
+}
+
+EAPI int
+ecore_x_netwm_visible_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (name)
+ *name = ecore_x_window_prop_string_get(win,
+ ECORE_X_ATOM_NET_WM_VISIBLE_NAME);
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME,
+ name);
+}
+
+EAPI int
+ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (name)
+ {
+ *name =
+ ecore_x_window_prop_string_get(win,
+ ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME);
+ }
+
+ return 1;
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_sync_counter_get(Ecore_X_Window win,
+ Ecore_X_Sync_Counter *counter)
+{
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
+ &tmp, 1))
+ return EINA_FALSE;
+
+ if (counter) *counter = tmp;
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_allowed_action_isset(Ecore_X_Window win,
+ Ecore_X_Action action)
+{
+ int num = 0, i = 0;
+ Ecore_X_Atom *atoms, atom;
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ num =
+ ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atoms);
+ if (num <= 0) return EINA_FALSE;
+
+ atom = _ecore_xcb_netwm_action_atom_get(action);
+ for (i = 0; i < num; i++)
+ {
+ if (atoms[i] == atom)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+ if (atoms) free(atoms);
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_allowed_action_get(Ecore_X_Window win,
+ Ecore_X_Action **action,
+ unsigned int *num)
+{
+ Ecore_X_Atom *atoms;
+ int num_ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (num) *num = 0;
+ if (action) *action = NULL;
+
+ num_ret =
+ ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
+ &atoms);
+ if (num_ret <= 0) return EINA_FALSE;
+ if (action)
+ {
+ *action = malloc(num_ret * sizeof(Ecore_X_Action));
+ if (*action)
+ {
+ int i = 0;
+
+ for (i = 0; i < num_ret; i++)
+ (*action)[i] = _ecore_xcb_netwm_action_atom_get(atoms[i]);
+ }
+ if (num) *num = num_ret;
+ }
+ free(atoms);
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_allowed_action_set(Ecore_X_Window win,
+ Ecore_X_Action *action,
+ unsigned int num)
+{
+ Ecore_X_Atom *set;
+ unsigned int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!num)
+ {
+ ecore_x_window_prop_property_del(win,
+ ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS);
+ return;
+ }
+
+ set = malloc(num * sizeof(Ecore_X_Atom));
+ if (!set) return;
+
+ for (i = 0; i < num; i++)
+ set[i] = _ecore_xcb_netwm_action_atom_get(action[i]);
+
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
+ set, num);
+ free(set);
+}
+
+/* local functions */
+int
+_ecore_xcb_netwm_startup_info_begin(Ecore_X_Window win EINA_UNUSED,
+ uint8_t data EINA_UNUSED)
+{
+ // TODO: TBD
+ return 1;
+}
+
+int
+_ecore_xcb_netwm_startup_info(Ecore_X_Window win EINA_UNUSED,
+ uint8_t data EINA_UNUSED)
+{
+ // TODO: TBD
+ return 1;
+}
+
+/* static void */
+/* _ecore_xcb_netwm_startup_info_free(void *data) */
+/* { */
+/* Ecore_Xcb_Startup_Info *info; */
+
+/* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
+
+/* if (!(info = data)) return; */
+/* if (info->buffer) free(info->buffer); */
+/* if (info->id) free(info->id); */
+/* if (info->name) free(info->name); */
+/* if (info->bin) free(info->bin); */
+/* if (info->icon) free(info->icon); */
+/* if (info->description) free(info->description); */
+/* if (info->wmclass) free(info->wmclass); */
+/* free(info); */
+/* } */
+
+static Ecore_X_Atom
+_ecore_xcb_netwm_window_type_atom_get(Ecore_X_Window_Type type)
+{
+ switch (type)
+ {
+ case ECORE_X_WINDOW_TYPE_DESKTOP:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP;
+
+ case ECORE_X_WINDOW_TYPE_DOCK:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK;
+
+ case ECORE_X_WINDOW_TYPE_TOOLBAR:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;
+
+ case ECORE_X_WINDOW_TYPE_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU;
+
+ case ECORE_X_WINDOW_TYPE_UTILITY:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY;
+
+ case ECORE_X_WINDOW_TYPE_SPLASH:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH;
+
+ case ECORE_X_WINDOW_TYPE_DIALOG:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG;
+
+ case ECORE_X_WINDOW_TYPE_NORMAL:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL;
+
+ case ECORE_X_WINDOW_TYPE_DROPDOWN_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+
+ case ECORE_X_WINDOW_TYPE_POPUP_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU;
+
+ case ECORE_X_WINDOW_TYPE_TOOLTIP:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP;
+
+ case ECORE_X_WINDOW_TYPE_NOTIFICATION:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION;
+
+ case ECORE_X_WINDOW_TYPE_COMBO:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO;
+
+ case ECORE_X_WINDOW_TYPE_DND:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND;
+
+ default:
+ return 0;
+ }
+}
+
+static Ecore_X_Window_Type
+_ecore_xcb_netwm_window_type_type_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP)
+ return ECORE_X_WINDOW_TYPE_DESKTOP;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK)
+ return ECORE_X_WINDOW_TYPE_DOCK;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR)
+ return ECORE_X_WINDOW_TYPE_TOOLBAR;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU)
+ return ECORE_X_WINDOW_TYPE_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY)
+ return ECORE_X_WINDOW_TYPE_UTILITY;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH)
+ return ECORE_X_WINDOW_TYPE_SPLASH;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG)
+ return ECORE_X_WINDOW_TYPE_DIALOG;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL)
+ return ECORE_X_WINDOW_TYPE_NORMAL;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
+ return ECORE_X_WINDOW_TYPE_DROPDOWN_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU)
+ return ECORE_X_WINDOW_TYPE_POPUP_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP)
+ return ECORE_X_WINDOW_TYPE_TOOLTIP;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION)
+ return ECORE_X_WINDOW_TYPE_NOTIFICATION;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO)
+ return ECORE_X_WINDOW_TYPE_COMBO;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND)
+ return ECORE_X_WINDOW_TYPE_DND;
+ else
+ return ECORE_X_WINDOW_TYPE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_netwm_window_state_atom_get(Ecore_X_Window_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_WINDOW_STATE_MODAL:
+ return ECORE_X_ATOM_NET_WM_STATE_MODAL;
+
+ case ECORE_X_WINDOW_STATE_STICKY:
+ return ECORE_X_ATOM_NET_WM_STATE_STICKY;
+
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
+ return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT;
+
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
+ return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ;
+
+ case ECORE_X_WINDOW_STATE_SHADED:
+ return ECORE_X_ATOM_NET_WM_STATE_SHADED;
+
+ case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
+ return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR;
+
+ case ECORE_X_WINDOW_STATE_SKIP_PAGER:
+ return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER;
+
+ case ECORE_X_WINDOW_STATE_HIDDEN:
+ return ECORE_X_ATOM_NET_WM_STATE_HIDDEN;
+
+ case ECORE_X_WINDOW_STATE_FULLSCREEN:
+ return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN;
+
+ case ECORE_X_WINDOW_STATE_ABOVE:
+ return ECORE_X_ATOM_NET_WM_STATE_ABOVE;
+
+ case ECORE_X_WINDOW_STATE_BELOW:
+ return ECORE_X_ATOM_NET_WM_STATE_BELOW;
+
+ case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION:
+ return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION;
+
+ default:
+ return 0;
+ }
+}
+
+Ecore_X_Window_State
+_ecore_xcb_netwm_window_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_NET_WM_STATE_MODAL)
+ return ECORE_X_WINDOW_STATE_MODAL;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_STICKY)
+ return ECORE_X_WINDOW_STATE_STICKY;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
+ return ECORE_X_WINDOW_STATE_MAXIMIZED_VERT;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
+ return ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_SHADED)
+ return ECORE_X_WINDOW_STATE_SHADED;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR)
+ return ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER)
+ return ECORE_X_WINDOW_STATE_SKIP_PAGER;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_HIDDEN)
+ return ECORE_X_WINDOW_STATE_HIDDEN;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN)
+ return ECORE_X_WINDOW_STATE_FULLSCREEN;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_ABOVE)
+ return ECORE_X_WINDOW_STATE_ABOVE;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_BELOW)
+ return ECORE_X_WINDOW_STATE_BELOW;
+ else if (atom == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION)
+ return ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION;
+ else
+ return ECORE_X_WINDOW_STATE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_netwm_action_atom_get(Ecore_X_Action action)
+{
+ switch (action)
+ {
+ case ECORE_X_ACTION_MOVE:
+ return ECORE_X_ATOM_NET_WM_ACTION_MOVE;
+
+ case ECORE_X_ACTION_RESIZE:
+ return ECORE_X_ATOM_NET_WM_ACTION_RESIZE;
+
+ case ECORE_X_ACTION_MINIMIZE:
+ return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;
+
+ case ECORE_X_ACTION_SHADE:
+ return ECORE_X_ATOM_NET_WM_ACTION_SHADE;
+
+ case ECORE_X_ACTION_STICK:
+ return ECORE_X_ATOM_NET_WM_ACTION_STICK;
+
+ case ECORE_X_ACTION_MAXIMIZE_HORZ:
+ return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;
+
+ case ECORE_X_ACTION_MAXIMIZE_VERT:
+ return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;
+
+ case ECORE_X_ACTION_FULLSCREEN:
+ return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;
+
+ case ECORE_X_ACTION_CHANGE_DESKTOP:
+ return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;
+
+ case ECORE_X_ACTION_CLOSE:
+ return ECORE_X_ATOM_NET_WM_ACTION_CLOSE;
+
+ case ECORE_X_ACTION_ABOVE:
+ return ECORE_X_ATOM_NET_WM_ACTION_ABOVE;
+
+ case ECORE_X_ACTION_BELOW:
+ return ECORE_X_ATOM_NET_WM_ACTION_BELOW;
+
+ default:
+ return 0;
+ }
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c
new file mode 100644
index 0000000000..f9bf525f7a
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c
@@ -0,0 +1,128 @@
+#include "ecore_xcb_private.h"
+
+/**
+ * @defgroup Ecore_X_Pixmap_Group X Pixmap Functions
+ *
+ * Functions that operate on pixmaps.
+ */
+
+/**
+ * Creates a new pixmap.
+ * @param win Window used to determine which screen of the display the
+ * pixmap should be created on. If 0, the default root window
+ * is used.
+ * @param w Width of the new pixmap.
+ * @param h Height of the new pixmap.
+ * @param dep Depth of the pixmap. If 0, the default depth of the default
+ * screen is used.
+ * @return New pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI Ecore_X_Pixmap
+ecore_x_pixmap_new(Ecore_X_Window win,
+ int w,
+ int h,
+ int dep)
+{
+ Ecore_X_Pixmap pmap;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (win == 0) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ if (dep == 0) dep = ((xcb_screen_t *)_ecore_xcb_screen)->root_depth;
+
+ pmap = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, dep, pmap, win, w, h);
+
+// ecore_x_flush();
+ return pmap;
+}
+
+/**
+ * Deletes the reference to the given pixmap.
+ *
+ * If no other clients have a reference to the given pixmap, the server
+ * will destroy it.
+ *
+ * @param pmap The given pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_free(Ecore_X_Pixmap pmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_free_pixmap(_ecore_xcb_conn, pmap);
+// ecore_x_flush();
+}
+
+/**
+ * Pastes a rectangular area of the given pixmap onto the given drawable.
+ * @param pmap The given pixmap.
+ * @param dest The given drawable.
+ * @param gc The graphics context which governs which operation will
+ * be used to paste the area onto the drawable.
+ * @param sx The X position of the area on the pixmap.
+ * @param sy The Y position of the area on the pixmap.
+ * @param w The width of the area.
+ * @param h The height of the area.
+ * @param dx The X position at which to paste the area on @p dest.
+ * @param dy The Y position at which to paste the area on @p dest.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_paste(Ecore_X_Pixmap pmap,
+ Ecore_X_Drawable dest,
+ Ecore_X_GC gc,
+ int sx,
+ int sy,
+ int w,
+ int h,
+ int dx,
+ int dy)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_copy_area(_ecore_xcb_conn, pmap, dest, gc, sx, sy, dx, dy, w, h);
+// ecore_x_flush();
+}
+
+/**
+ * Retrieves the size of the given pixmap.
+ * @param pmap The given pixmap.
+ * @param x Pointer to an integer in which to store the X position.
+ * @param y Pointer to an integer in which to store the Y position.
+ * @param w Pointer to an integer in which to store the width.
+ * @param h Pointer to an integer in which to store the height.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (pmap)
+ ecore_x_drawable_geometry_get(pmap, x, y, w, h);
+}
+
+/**
+ * Retrieves the depth of the given pixmap.
+ * @param pmap The given pixmap.
+ * @return The depth of the pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI int
+ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_drawable_depth_get(pmap);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_private.h b/src/lib/ecore_x/xcb/ecore_xcb_private.h
new file mode 100644
index 0000000000..240210ca0d
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_private.h
@@ -0,0 +1,468 @@
+#ifndef __ECORE_XCB_PRIVATE_H__
+# define __ECORE_XCB_PRIVATE_H__
+
+//# define LOGFNS 1
+
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+# include <unistd.h> // included for close & gethostname functions
+
+/* generic xcb includes */
+# include <xcb/xcb.h>
+# include <xcb/bigreq.h>
+# include <xcb/shm.h>
+# include <xcb/xcb_image.h>
+
+/* EFL includes */
+# include "Ecore.h"
+# include "Ecore_Input.h"
+# include "Ecore_X.h"
+
+/* logging */
+extern int _ecore_xcb_log_dom;
+
+# ifdef ECORE_XCB_DEFAULT_LOG_COLOR
+# undef ECORE_XCB_DEFAULT_LOG_COLOR
+# endif
+# define ECORE_XCB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+# ifdef ERR
+# undef ERR
+# endif
+# define ERR(...) EINA_LOG_DOM_ERR(_ecore_xcb_log_dom, __VA_ARGS__)
+
+# ifdef DBG
+# undef DBG
+# endif
+# define DBG(...) EINA_LOG_DOM_DBG(_ecore_xcb_log_dom, __VA_ARGS__)
+
+# ifdef INF
+# undef INF
+# endif
+# define INF(...) EINA_LOG_DOM_INFO(_ecore_xcb_log_dom, __VA_ARGS__)
+
+# ifdef WRN
+# undef WRN
+# endif
+# define WRN(...) EINA_LOG_DOM_WARN(_ecore_xcb_log_dom, __VA_ARGS__)
+
+# ifdef CRIT
+# undef CRIT
+# endif
+# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_xcb_log_dom, __VA_ARGS__)
+
+# ifdef LOGFNS
+# include <stdio.h>
+# define LOGFN(fl, ln, fn) printf("-ECORE-XCB: %25s: %5i - %s\n", fl, ln, fn);
+# else
+# define LOGFN(fl, ln, fn)
+# endif
+
+# ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 256
+# endif
+
+# ifndef MIN
+# define MIN(x, y) (((x) > (y)) ? (y) : (x))
+# endif
+
+# ifndef MAX
+# define MAX(a, b) ((a < b) ? b : a)
+# endif
+
+#define CHECK_XCB_CONN \
+ { \
+ if (xcb_connection_has_error(_ecore_xcb_conn)) \
+ { \
+ DBG("XCB Connection Has Error !!"); \
+ _ecore_xcb_io_error_handle(NULL); \
+ } \
+ }
+
+/* enums */
+typedef enum _Ecore_Xcb_Encoding_Style Ecore_Xcb_Encoding_Style;
+
+enum _Ecore_Xcb_Encoding_Style
+{
+ XcbStringStyle,
+ XcbCompoundTextStyle,
+ XcbTextStyle,
+ XcbStdICCTextStyle,
+ XcbUTF8StringStyle
+};
+
+/* structures */
+typedef struct _Ecore_X_DND_Source Ecore_X_DND_Source;
+typedef struct _Ecore_X_DND_Target Ecore_X_DND_Target;
+typedef struct _Ecore_X_Selection_Intern Ecore_X_Selection_Intern;
+typedef struct _Ecore_X_Selection_Converter Ecore_X_Selection_Converter;
+typedef struct _Ecore_X_Selection_Parser Ecore_X_Selection_Parser;
+typedef struct _Ecore_Xcb_Textproperty Ecore_Xcb_Textproperty;
+
+struct _Ecore_X_DND_Source
+{
+ int version;
+ Ecore_X_Window win, dest;
+
+ enum
+ {
+ ECORE_X_DND_SOURCE_IDLE,
+ ECORE_X_DND_SOURCE_DRAGGING,
+ ECORE_X_DND_SOURCE_DROPPED,
+ ECORE_X_DND_SOURCE_CONVERTING
+ } state;
+
+ struct
+ {
+ short x, y;
+ unsigned short width, height;
+ } rectangle;
+
+ struct
+ {
+ Ecore_X_Window window;
+ int x, y;
+ } prev;
+
+ Ecore_X_Time time;
+
+ Ecore_X_Atom action, accepted_action;
+
+ int will_accept, suppress;
+ int await_status;
+};
+
+struct _Ecore_X_DND_Target
+{
+ int version;
+ Ecore_X_Window win, source;
+
+ enum
+ {
+ ECORE_X_DND_TARGET_IDLE,
+ ECORE_X_DND_TARGET_ENTERED
+ } state;
+
+ struct
+ {
+ int x, y;
+ } pos;
+
+ Ecore_X_Time time;
+
+ Ecore_X_Atom action, accepted_action;
+ int will_accept;
+};
+
+struct _Ecore_X_Selection_Intern
+{
+ Ecore_X_Window win;
+ Ecore_X_Atom selection;
+ unsigned char *data;
+ int length;
+ Ecore_X_Time time;
+};
+
+struct _Ecore_X_Selection_Converter
+{
+ Ecore_X_Atom target;
+ Eina_Bool (*convert)(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *type,
+ int *size_type);
+ Ecore_X_Selection_Converter *next;
+};
+
+struct _Ecore_X_Selection_Parser
+{
+ char *target;
+ void *(*parse)(const char *target, void *data, int size, int format);
+ Ecore_X_Selection_Parser *next;
+};
+
+struct _Ecore_Xcb_Textproperty
+{
+ char *value;
+ Ecore_X_Atom encoding;
+ unsigned int format, nitems;
+};
+
+/* external variables */
+extern Ecore_X_Connection *_ecore_xcb_conn;
+extern Ecore_X_Screen *_ecore_xcb_screen;
+extern double _ecore_xcb_double_click_time;
+extern int16_t _ecore_xcb_event_last_root_x;
+extern int16_t _ecore_xcb_event_last_root_y;
+
+/* external variables for extension events */
+extern int _ecore_xcb_event_damage;
+extern int _ecore_xcb_event_randr;
+extern int _ecore_xcb_event_screensaver;
+extern int _ecore_xcb_event_shape;
+extern int _ecore_xcb_event_sync;
+extern int _ecore_xcb_event_xfixes;
+extern int _ecore_xcb_event_input;
+extern int _ecore_xcb_event_gesture;
+
+extern Ecore_X_Atom _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_NUM];
+
+extern int _ecore_xcb_button_grabs_num;
+extern int _ecore_xcb_key_grabs_num;
+extern Ecore_X_Window *_ecore_xcb_button_grabs;
+extern Ecore_X_Window *_ecore_xcb_key_grabs;
+extern Eina_Bool (*_ecore_xcb_window_grab_replay_func)(void *data,
+ int type,
+ void *event);
+extern void *_ecore_xcb_window_grab_replay_data;
+
+/* private function prototypes */
+void _ecore_xcb_error_handler_init(void);
+void _ecore_xcb_error_handler_shutdown(void);
+
+void _ecore_xcb_atoms_init(void);
+void _ecore_xcb_atoms_finalize(void);
+
+void _ecore_xcb_extensions_init(void);
+void _ecore_xcb_extensions_finalize(void);
+
+void _ecore_xcb_shape_init(void);
+void _ecore_xcb_shape_finalize(void);
+
+void _ecore_xcb_screensaver_init(void);
+void _ecore_xcb_screensaver_finalize(void);
+
+void _ecore_xcb_sync_init(void);
+void _ecore_xcb_sync_finalize(void);
+void _ecore_xcb_sync_magic_send(int val,
+ Ecore_X_Window win);
+
+void _ecore_xcb_render_init(void);
+void _ecore_xcb_render_finalize(void);
+Eina_Bool _ecore_xcb_render_argb_get(void);
+Eina_Bool _ecore_xcb_render_anim_get(void);
+Eina_Bool _ecore_xcb_render_avail_get(void);
+
+Eina_Bool _ecore_xcb_render_visual_supports_alpha(Ecore_X_Visual visual);
+uint32_t _ecore_xcb_render_find_visual_id(int type,
+ Eina_Bool check_alpha);
+Ecore_X_Visual *_ecore_xcb_render_visual_get(int visual_id);
+
+void _ecore_xcb_randr_init(void);
+void _ecore_xcb_randr_finalize(void);
+
+void _ecore_xcb_gesture_init(void);
+void _ecore_xcb_gesture_finalize(void);
+void _ecore_xcb_gesture_shutdown(void);
+
+void _ecore_xcb_xfixes_init(void);
+void _ecore_xcb_xfixes_finalize(void);
+Eina_Bool _ecore_xcb_xfixes_avail_get(void);
+
+void _ecore_xcb_damage_init(void);
+void _ecore_xcb_damage_finalize(void);
+
+void _ecore_xcb_composite_init(void);
+void _ecore_xcb_composite_finalize(void);
+
+void _ecore_xcb_dpms_init(void);
+void _ecore_xcb_dpms_finalize(void);
+
+void _ecore_xcb_cursor_init(void);
+void _ecore_xcb_cursor_finalize(void);
+
+void _ecore_xcb_xinerama_init(void);
+void _ecore_xcb_xinerama_finalize(void);
+
+void _ecore_xcb_dnd_init(void);
+void _ecore_xcb_dnd_shutdown(void);
+Ecore_X_DND_Source *_ecore_xcb_dnd_source_get(void);
+Ecore_X_DND_Target *_ecore_xcb_dnd_target_get(void);
+void _ecore_xcb_dnd_drag(Ecore_X_Window root,
+ int x,
+ int y);
+
+void _ecore_xcb_selection_init(void);
+void _ecore_xcb_selection_shutdown(void);
+void *_ecore_xcb_selection_parse(const char *target,
+ void *data,
+ int size,
+ int format);
+char *_ecore_xcb_selection_target_get(Ecore_X_Atom target);
+Ecore_X_Selection_Intern *_ecore_xcb_selection_get(Ecore_X_Atom selection);
+
+# ifdef HAVE_ICONV
+Eina_Bool _ecore_xcb_utf8_textlist_to_textproperty(char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret);
+# endif
+Eina_Bool _ecore_xcb_mb_textlist_to_textproperty(char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret);
+Eina_Bool _ecore_xcb_textlist_to_textproperty(const char *type,
+ char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret);
+
+# ifdef HAVE_ICONV
+Eina_Bool _ecore_xcb_utf8_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ char ***list_ret,
+ int *count_ret);
+# endif
+Eina_Bool _ecore_xcb_mb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ char ***list_ret,
+ int *count_ret);
+Eina_Bool _ecore_xcb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ const char *type,
+ char ***list_ret,
+ int *count_ret);
+
+void _ecore_xcb_events_init(void);
+void _ecore_xcb_events_shutdown(void);
+void _ecore_xcb_events_handle(xcb_generic_event_t *ev);
+Ecore_X_Time _ecore_xcb_events_last_time_get(void);
+unsigned int _ecore_xcb_events_modifiers_get(unsigned int state);
+void _ecore_xcb_event_mouse_move(uint16_t timestamp,
+ uint16_t modifiers,
+ int16_t x,
+ int16_t y,
+ int16_t root_x,
+ int16_t root_y,
+ xcb_window_t event_win,
+ xcb_window_t win,
+ xcb_window_t root_win,
+ uint8_t same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ int16_t mx,
+ int16_t my,
+ int16_t mrx,
+ int16_t mry);
+Ecore_Event_Mouse_Button *_ecore_xcb_event_mouse_button(int event,
+ uint16_t timestamp,
+ uint16_t modifiers,
+ xcb_button_t buttons,
+ int16_t x,
+ int16_t y,
+ int16_t root_x,
+ int16_t root_y,
+ xcb_window_t event_win,
+ xcb_window_t win,
+ xcb_window_t root_win,
+ uint8_t same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ int16_t mx,
+ int16_t my,
+ int16_t mrx,
+ int16_t mry);
+
+void _ecore_xcb_keymap_init(void);
+void _ecore_xcb_keymap_finalize(void);
+void _ecore_xcb_keymap_shutdown(void);
+void _ecore_xcb_keymap_refresh(xcb_mapping_notify_event_t *event);
+xcb_keysym_t _ecore_xcb_keymap_keycode_to_keysym(xcb_keycode_t keycode,
+ int col);
+xcb_keycode_t *_ecore_xcb_keymap_keysym_to_keycode(xcb_keysym_t keysym);
+char *_ecore_xcb_keymap_keysym_to_string(xcb_keysym_t keysym);
+xcb_keycode_t _ecore_xcb_keymap_string_to_keycode(const char *key);
+int _ecore_xcb_keymap_lookup_string(xcb_keycode_t keycode,
+ int state,
+ char *buffer,
+ int bytes,
+ xcb_keysym_t *sym);
+
+void _ecore_xcb_input_init(void);
+void _ecore_xcb_input_finalize(void);
+void _ecore_xcb_input_shutdown(void);
+# ifdef ECORE_XCB_XINPUT
+void _ecore_xcb_input_handle_event(xcb_generic_event_t *event);
+# else
+void _ecore_xcb_input_handle_event(xcb_generic_event_t *event);
+# endif
+
+void _ecore_xcb_dri_init(void);
+void _ecore_xcb_dri_finalize(void);
+
+void _ecore_xcb_xtest_init(void);
+void _ecore_xcb_xtest_finalize(void);
+
+Ecore_X_Window _ecore_xcb_window_root_of_screen_get(int screen);
+void _ecore_xcb_window_prop_string_utf8_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ const char *str);
+Ecore_X_Visual _ecore_xcb_window_visual_get(Ecore_X_Window win);
+void _ecore_xcb_window_button_grab_remove(Ecore_X_Window win);
+void _ecore_xcb_window_key_grab_remove(Ecore_X_Window win);
+void _ecore_xcb_window_grab_allow_events(Ecore_X_Window event_win,
+ Ecore_X_Window child_win,
+ int type,
+ void *event,
+ Ecore_X_Time timestamp);
+
+int _ecore_xcb_netwm_startup_info_begin(Ecore_X_Window win,
+ uint8_t data);
+int _ecore_xcb_netwm_startup_info(Ecore_X_Window win,
+ uint8_t data);
+Ecore_X_Window_State _ecore_xcb_netwm_window_state_get(Ecore_X_Atom atom);
+
+int _ecore_xcb_error_handle(xcb_generic_error_t *err);
+int _ecore_xcb_io_error_handle(xcb_generic_error_t *err);
+
+xcb_image_t *_ecore_xcb_image_create_native(int w,
+ int h,
+ xcb_image_format_t format,
+ uint8_t depth,
+ void *base,
+ uint32_t bytes,
+ uint8_t *data);
+
+void _ecore_xcb_xdefaults_init(void);
+void _ecore_xcb_xdefaults_shutdown(void);
+char *_ecore_xcb_xdefaults_string_get(const char *prog,
+ const char *param);
+int _ecore_xcb_xdefaults_int_get(const char *prog,
+ const char *param);
+
+void _ecore_xcb_modifiers_get(void);
+
+#endif
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_randr.c b/src/lib/ecore_x/xcb/ecore_xcb_randr.c
new file mode 100644
index 0000000000..a2a4e6271f
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_randr.c
@@ -0,0 +1,3807 @@
+/* TODO: List of missing functions
+ *
+ * ecore_x_randr_crtc_clone_set
+ * ecore_x_randr_output_crtc_set
+ * ecore_x_randr_edid_version_get
+ * ecore_x_randr_edid_info_has_valid_checksum
+ * ecore_x_randr_edid_manufacturer_name_get
+ * ecore_x_randr_edid_display_ascii_get
+ * ecore_x_randr_edid_display_serial_get
+ * ecore_x_randr_edid_model_get
+ * ecore_x_randr_edid_manufacturer_serial_number_get
+ * ecore_x_randr_edid_manufacturer_model_get
+ * ecore_x_randr_edid_dpms_available_get
+ * ecore_x_randr_edid_dpms_standby_available_get
+ * ecore_x_randr_edid_dpms_suspend_available_get
+ * ecore_x_randr_edid_dpms_off_available_get
+ * ecore_x_randr_edid_display_aspect_ratio_preferred_get
+ * ecore_x_randr_edid_display_aspect_ratios_get
+ * ecore_x_randr_edid_display_colorscheme_get
+ * ecore_x_randr_edid_display_type_digital_get
+ * ecore_x_randr_edid_display_interface_type_get
+ * ecore_x_randr_screen_backlight_level_set
+ * ecore_x_randr_output_subpixel_order_get
+ * ecore_x_randr_output_wired_clones_get
+ * ecore_x_randr_output_compatibility_list_get
+ * ecore_x_randr_output_signal_formats_get
+ * ecore_x_randr_output_signal_format_set
+ * ecore_x_randr_output_signal_properties_get
+ * ecore_x_randr_output_connector_number_get
+ * ecore_x_randr_output_connector_type_get
+ * ecore_x_randr_crtc_panning_area_get
+ * ecore_x_randr_crtc_panning_area_set
+ * ecore_x_randr_crtc_tracking_area_get
+ * ecore_x_randr_crtc_tracking_area_set
+ * ecore_x_randr_crtc_border_area_get
+ * ecore_x_randr_crtc_border_area_set
+ */
+
+#include "ecore_xcb_private.h"
+# ifdef ECORE_XCB_RANDR
+# include <xcb/randr.h>
+# endif
+
+#define Ecore_X_Randr_None 0
+#define Ecore_X_Randr_Unset -1
+
+#define RANDR_1_1 ((1 << 16) | 1)
+#define RANDR_1_2 ((1 << 16) | 2)
+#define RANDR_1_3 ((1 << 16) | 3)
+
+#define RANDR_CHECK_1_1_RET(ret) if (_randr_version < RANDR_1_1) return ret
+#define RANDR_CHECK_1_2_RET(ret) if (_randr_version < RANDR_1_2) return ret
+#define RANDR_CHECK_1_3_RET(ret) if (_randr_version < RANDR_1_3) return ret
+
+#define ECORE_X_RANDR_EDID_VERSION_13 ((1 << 8) | 3)
+#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR 0x12
+#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR 0x13
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK 0x36
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE 3
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT 5
+#define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13
+
+#define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
+ for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3 * 18)); block += 18)
+
+#define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \
+ _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
+ if ((block[0] == 0) && (block[1] == 0))
+
+/* local function prototypes */
+static Eina_Bool _ecore_xcb_randr_output_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Output output);
+static Eina_Bool _ecore_xcb_randr_crtc_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc);
+static Eina_Bool _ecore_xcb_randr_root_validate(Ecore_X_Window root);
+static int _ecore_xcb_randr_root_to_screen(Ecore_X_Window root);
+#ifdef ECORE_XCB_RANDR
+static xcb_randr_get_screen_resources_reply_t *_ecore_xcb_randr_12_get_resources(Ecore_X_Window win);
+static xcb_randr_get_screen_resources_current_reply_t *_ecore_xcb_randr_13_get_resources(Ecore_X_Window win);
+#endif
+static xcb_timestamp_t _ecore_xcb_randr_12_get_resource_timestamp(Ecore_X_Window win);
+static xcb_timestamp_t _ecore_xcb_randr_13_get_resource_timestamp(Ecore_X_Window win);
+
+static Ecore_X_Randr_Mode *_ecore_xcb_randr_12_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred);
+static Ecore_X_Randr_Mode *_ecore_xcb_randr_13_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred);
+static Ecore_X_Randr_Mode_Info *_ecore_xcb_randr_12_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode);
+static Ecore_X_Randr_Mode_Info *_ecore_xcb_randr_13_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode);
+static Ecore_X_Randr_Mode_Info **_ecore_xcb_randr_12_modes_info_get(Ecore_X_Window root,
+ int *num);
+static Ecore_X_Randr_Mode_Info **_ecore_xcb_randr_13_modes_info_get(Ecore_X_Window root,
+ int *num);
+static void _ecore_xcb_randr_12_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h);
+static void _ecore_xcb_randr_13_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h);
+static Ecore_X_Randr_Output *_ecore_xcb_randr_12_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num);
+static Ecore_X_Randr_Output *_ecore_xcb_randr_13_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num);
+static Ecore_X_Randr_Crtc *_ecore_xcb_randr_12_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num);
+static Ecore_X_Randr_Crtc *_ecore_xcb_randr_13_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num);
+static char *_ecore_xcb_randr_12_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len);
+static char *_ecore_xcb_randr_13_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len);
+static Ecore_X_Randr_Connection_Status _ecore_xcb_randr_12_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output);
+static Ecore_X_Randr_Connection_Status _ecore_xcb_randr_13_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output);
+static Ecore_X_Randr_Output *_ecore_xcb_randr_12_outputs_get(Ecore_X_Window root,
+ int *num);
+static Ecore_X_Randr_Output *_ecore_xcb_randr_13_outputs_get(Ecore_X_Window root,
+ int *num);
+static Ecore_X_Randr_Crtc _ecore_xcb_randr_12_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output);
+static Ecore_X_Randr_Crtc _ecore_xcb_randr_13_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output);
+
+/* local variables */
+static Eina_Bool _randr_avail = EINA_FALSE;
+static int _randr_version = -1;
+
+/* external variables */
+int _ecore_xcb_event_randr = -1;
+
+void
+_ecore_xcb_randr_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_RANDR
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_randr_id);
+#endif
+}
+
+void
+_ecore_xcb_randr_finalize(void)
+{
+#ifdef ECORE_XCB_RANDR
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_RANDR
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_randr_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_randr_query_version_cookie_t cookie;
+ xcb_randr_query_version_reply_t *reply;
+
+ cookie =
+ xcb_randr_query_version_unchecked(_ecore_xcb_conn,
+ XCB_RANDR_MAJOR_VERSION,
+ XCB_RANDR_MINOR_VERSION);
+ reply = xcb_randr_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if ((reply->major_version >= XCB_RANDR_MAJOR_VERSION) &&
+ (reply->minor_version >= XCB_RANDR_MINOR_VERSION))
+ _randr_avail = EINA_TRUE;
+
+ _randr_version =
+ ((reply->major_version << 16) | reply->minor_version);
+
+ free(reply);
+ }
+
+ if (_randr_avail)
+ _ecore_xcb_event_randr = ext_reply->first_event;
+ }
+#endif
+}
+
+static Eina_Bool
+#ifdef ECORE_XCB_RANDR
+_ecore_xcb_randr_root_validate(Ecore_X_Window root)
+#else
+_ecore_xcb_randr_root_validate(Ecore_X_Window root EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Randr_Screen scr = -1;
+# define RANDR_VALIDATE_ROOT(screen, root) \
+ ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1)
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_RANDR
+ if ((root) && RANDR_VALIDATE_ROOT(scr, root))
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
+static int
+_ecore_xcb_randr_root_to_screen(Ecore_X_Window root)
+{
+ int count = 0, num = 0;
+
+ CHECK_XCB_CONN;
+
+ count = xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn));
+ for (num = 0; num < count; num++)
+ if (_ecore_xcb_window_root_of_screen_get(num) == root)
+ return num;
+
+ return -1;
+}
+
+/* public functions */
+
+/*
+ * @brief Query whether RandR is available or not.
+ *
+ * @return @c EINA_TRUE if extension is available, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_query(void)
+{
+ return _randr_avail;
+}
+
+/*
+ * @return version of the RandRR extension supported by the server or,
+ * in case RandRR extension is not available, Ecore_X_Randr_Unset (=-1).
+ * bit version information: 31 MAJOR 16 | 15 MINOR 0
+ */
+EAPI int
+ecore_x_randr_version_get(void)
+{
+ return _randr_version;
+}
+
+/*
+ * @param root window which's primary output will be queried
+ */
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root)
+{
+ int ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ ret = reply->rotations;
+ free(reply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @return the current orientation of the root window's screen primary output
+ */
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root)
+{
+ int ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ ret = reply->rotation;
+ free(reply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @brief Sets a given screen's primary output's orientation.
+ *
+ * @param root Window which's screen's primary output will be queried.
+ * @param orientation Orientation which should be set for the root window's
+ * screen primary output.
+ * @return @c EINA_TRUE if the primary output's orientation could be
+ * successfully altered.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root,
+ Ecore_X_Randr_Orientation orientation)
+{
+ int ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ xcb_randr_set_screen_config_cookie_t scookie;
+ xcb_randr_set_screen_config_reply_t *sreply;
+
+ scookie =
+ xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
+ XCB_CURRENT_TIME,
+ reply->config_timestamp,
+ reply->sizeID, orientation,
+ reply->rate);
+ sreply =
+ xcb_randr_set_screen_config_reply(_ecore_xcb_conn, scookie, NULL);
+ if (!sreply)
+ ret = EINA_FALSE;
+ else
+ {
+ ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ?
+ EINA_TRUE : EINA_FALSE;
+ free(sreply);
+ }
+ free(reply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @brief gets a screen's primary output's possible sizes
+ * @param root window which's primary output will be queried
+ * @param num number of sizes reported as supported by the screen's primary output
+ * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL
+ */
+EAPI Ecore_X_Randr_Screen_Size_MM *
+ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root,
+ int *num)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+ Ecore_X_Randr_Screen_Size_MM *ret = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ int len = 0, i = 0;
+ xcb_randr_screen_size_t *sizes;
+
+ len = xcb_randr_get_screen_info_sizes_length(reply);
+ sizes = xcb_randr_get_screen_info_sizes(reply);
+ if ((!sizes) || (len <= 0))
+ {
+ free(reply);
+ return NULL;
+ }
+ if (num) *num = len;
+ ret = calloc(len, sizeof(Ecore_X_Randr_Screen_Size_MM));
+ if (!ret)
+ {
+ free(reply);
+ return NULL;
+ }
+ for (i = 0; i < len; i++)
+ {
+ ret[i].width = sizes[i].width;
+ ret[i].height = sizes[i].height;
+ ret[i].width_mm = sizes[i].mwidth;
+ ret[i].height_mm = sizes[i].mheight;
+ }
+
+ free(reply);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief get the current set size of a given screen's primary output
+ * @param root window which's primary output will be queried
+ * @param w the current size's width
+ * @param h the current size's height
+ * @param w_mm the current size's width in mm
+ * @param h_mm the current size's height in mm
+ * @param size_index of current set size to be used with ecore_x_randr_primary_output_size_set()
+ */
+EAPI void
+ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root,
+ int *w,
+ int *h,
+ int *w_mm,
+ int *h_mm,
+ int *size_index)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ int len = 0, idx = 0;
+ xcb_randr_screen_size_t *sizes;
+
+ len = xcb_randr_get_screen_info_sizes_length(reply);
+ sizes = xcb_randr_get_screen_info_sizes(reply);
+ if ((!sizes) || (len <= 0))
+ {
+ free(reply);
+ return;
+ }
+ idx = reply->sizeID;
+ if ((idx < len) && (idx >= 0))
+ {
+ if (w) *w = sizes[idx].width;
+ if (h) *h = sizes[idx].height;
+ if (w_mm) *w_mm = sizes[idx].mwidth;
+ if (h_mm) *h_mm = sizes[idx].mheight;
+ if (size_index) *size_index = idx;
+ }
+
+ free(reply);
+ }
+#endif
+}
+
+/*
+ * @brief Sets a given screen's primary output size, but disables all other
+ * outputs at the same time.
+ *
+ * @param root Window which's primary output will be queried.
+ * @param size_index Within the list of sizes reported as supported by the root
+ * window's screen primary output.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g.
+ * invalid times.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root,
+ int size_index)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (!((size_index >= 0) && (_ecore_xcb_randr_root_validate(root))))
+ return EINA_FALSE;
+
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ int len = 0;
+
+ len = xcb_randr_get_screen_info_sizes_length(reply);
+ if (len <= 0)
+ {
+ free(reply);
+ return EINA_FALSE;
+ }
+ if ((size_index < len) && (size_index >= 0))
+ {
+ xcb_randr_set_screen_config_cookie_t scookie;
+ xcb_randr_set_screen_config_reply_t *sreply;
+
+ scookie =
+ xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
+ XCB_CURRENT_TIME,
+ reply->config_timestamp,
+ size_index,
+ reply->rotation,
+ reply->rate);
+ sreply =
+ xcb_randr_set_screen_config_reply(_ecore_xcb_conn,
+ scookie, NULL);
+ if (!sreply)
+ ret = EINA_FALSE;
+ else
+ {
+ ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ?
+ EINA_TRUE : EINA_FALSE;
+ free(sreply);
+ }
+ }
+
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0
+ */
+EAPI Ecore_X_Randr_Refresh_Rate
+ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+ Ecore_X_Randr_Refresh_Rate ret = 0.0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (!_ecore_xcb_randr_root_validate(root)) return ret;
+
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ ret = reply->rate;
+ free(reply);
+ }
+
+ return ret;
+#else
+ return 0.0;
+#endif
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @param size_index referencing the size to query valid refresh rates for
+ * @return currently used refresh rate or - if request failed or RandRR is not available - NULL
+ */
+EAPI Ecore_X_Randr_Refresh_Rate *
+ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root,
+ int size_index,
+ int *num)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+ Ecore_X_Randr_Refresh_Rate *ret = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (!_ecore_xcb_randr_root_validate(root)) return ret;
+
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ int len = 0;
+
+ len = xcb_randr_get_screen_info_rates_length(reply);
+ if (num) *num = len;
+
+ ret = malloc(sizeof(Ecore_X_Randr_Refresh_Rate) * len);
+ if (ret)
+ {
+ xcb_randr_refresh_rates_iterator_t iter;
+ int i = 0;
+
+ iter = xcb_randr_get_screen_info_rates_iterator(reply);
+ while (i++ < size_index)
+ xcb_randr_refresh_rates_next(&iter);
+
+ memcpy(ret, xcb_randr_refresh_rates_rates(iter.data),
+ sizeof(Ecore_X_Randr_Refresh_Rate) * len);
+ }
+ free(reply);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief Sets the current primary output's refresh rate.
+ *
+ * @param root Window which's primary output will be queried.
+ * @param size_index Referencing the size to be set.
+ * @param rate The refresh rate to be set.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root,
+ int size_index,
+ Ecore_X_Randr_Refresh_Rate rate)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_info_cookie_t cookie;
+ xcb_randr_get_screen_info_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (_randr_version < RANDR_1_1) return EINA_FALSE;
+
+ cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ xcb_randr_set_screen_config_cookie_t scookie;
+ xcb_randr_set_screen_config_reply_t *sreply;
+
+ scookie =
+ xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
+ XCB_CURRENT_TIME,
+ reply->config_timestamp,
+ size_index,
+ reply->rotation, rate);
+ sreply =
+ xcb_randr_set_screen_config_reply(_ecore_xcb_conn,
+ scookie, NULL);
+ if (!sreply)
+ ret = EINA_FALSE;
+ else
+ {
+ ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ?
+ EINA_TRUE : EINA_FALSE;
+ free(sreply);
+ }
+ free(reply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @brief Free detailed mode information. The pointer handed in will be set to
+ * @c NULL after freeing the memory.
+ *
+ * @param mode_info The mode information that should be freed.
+ */
+EAPI void
+ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ RANDR_CHECK_1_2_RET();
+
+ if (!mode_info) return;
+
+ if (mode_info->name) free(mode_info->name);
+ free(mode_info);
+ mode_info = NULL;
+}
+
+/*
+ * @param root window which's screen should be queried
+ * @return Ecore_X_Randr_Ouptut_Id or - if query failed or none is set - Ecore_X_Randr_None
+ */
+EAPI Ecore_X_Randr_Output
+ecore_x_randr_primary_output_get(Ecore_X_Window root)
+{
+ Ecore_X_Randr_Output ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_output_primary_cookie_t cookie;
+ xcb_randr_get_output_primary_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_3_RET(Ecore_X_Randr_None);
+
+ if (!_ecore_xcb_randr_root_validate(root))
+ return Ecore_X_Randr_None;
+
+ cookie = xcb_randr_get_output_primary_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_output_primary_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ ret = reply->output;
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+/*
+ * @param root window which's screen should be queried
+ * @param output that should be set as given root window's screen primary output
+ */
+EAPI void
+ecore_x_randr_primary_output_set(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_3_RET();
+
+ if ((output) && (_ecore_xcb_randr_root_validate(root)))
+ xcb_randr_set_output_primary(_ecore_xcb_conn, root, output);
+#endif
+}
+
+EAPI Ecore_X_Randr_Mode *
+ecore_x_randr_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred)
+{
+ Ecore_X_Randr_Mode *modes = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (_randr_version >= RANDR_1_3)
+ {
+ modes =
+ _ecore_xcb_randr_13_output_modes_get(root, output, num, npreferred);
+ }
+ else if (_randr_version == RANDR_1_2)
+ {
+ modes =
+ _ecore_xcb_randr_12_output_modes_get(root, output, num, npreferred);
+ }
+#endif
+
+ return modes;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None))
+ return EINA_FALSE;
+
+ xcb_randr_add_output_mode(_ecore_xcb_conn, output, mode);
+ return EINA_TRUE;
+#endif
+ return EINA_FALSE;
+}
+
+/*
+ * @brief get detailed information for a given mode id
+ * @param root window which's screen's ressources are queried
+ * @param mode the XID which identifies the mode of interest
+ * @return mode's detailed information
+ */
+EAPI Ecore_X_Randr_Mode_Info *
+ecore_x_randr_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode)
+{
+ Ecore_X_Randr_Mode_Info *ret = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (!_ecore_xcb_randr_root_validate(root)) return NULL;
+
+ if (_randr_version >= RANDR_1_3)
+ ret = _ecore_xcb_randr_13_mode_info_get(root, mode);
+ else if (_randr_version == RANDR_1_2)
+ ret = _ecore_xcb_randr_12_mode_info_get(root, mode);
+#endif
+ return ret;
+}
+
+/*
+ * @brief add a mode to a display
+ * @param root window to which's screen's ressources are added
+ * @param mode_info
+ * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode
+ * adding failed.
+ * @since 1.2.0
+ */
+EAPI Ecore_X_Randr_Mode
+ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info)
+{
+ Ecore_X_Randr_Mode mode = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_create_mode_cookie_t cookie;
+ xcb_randr_create_mode_reply_t *reply;
+ xcb_randr_mode_info_t info;
+ int namelen = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (!mode_info) return Ecore_X_Randr_None;
+ if (!_ecore_xcb_randr_root_validate(root)) return Ecore_X_Randr_None;
+
+ namelen = strlen(mode_info->name);
+
+ memset(&info, 0, sizeof(info));
+ info.width = mode_info->width;
+ info.height = mode_info->height;
+ info.dot_clock = mode_info->dotClock;
+ info.hsync_start = mode_info->hSyncStart;
+ info.hsync_end = mode_info->hSyncEnd;
+ info.htotal = mode_info->hTotal;
+ info.hskew = mode_info->hSkew;
+ info.vsync_start = mode_info->vSyncStart;
+ info.vsync_end = mode_info->vSyncEnd;
+ info.vtotal = mode_info->vTotal;
+ info.mode_flags = mode_info->modeFlags;
+ info.name_len = namelen;
+
+ cookie =
+ xcb_randr_create_mode_unchecked(_ecore_xcb_conn, root, info,
+ namelen, mode_info->name);
+ reply = xcb_randr_create_mode_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ mode = mode_info->xid;
+ free(reply);
+ }
+#endif
+ return mode;
+}
+
+/*
+ * @brief get detailed information for all modes related to a root window's screen
+ * @param root window which's screen's ressources are queried
+ * @param num number of modes returned
+ * @return modes' information
+ */
+EAPI Ecore_X_Randr_Mode_Info **
+ecore_x_randr_modes_info_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Mode_Info **ret = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (!_ecore_xcb_randr_root_validate(root)) return NULL;
+
+ if (_randr_version >= RANDR_1_3)
+ ret = _ecore_xcb_randr_13_modes_info_get(root, num);
+ else if (_randr_version == RANDR_1_2)
+ ret = _ecore_xcb_randr_12_modes_info_get(root, num);
+#endif
+ return ret;
+}
+
+/**
+ * @brief Gets the width and hight of a given mode.
+ *
+ * @param root Window which's screen's ressources are queried.
+ * @param mode The mode which's size is to be looked up.
+ * @param w Width of given mode in px.
+ * @param h Height of given mode in px.
+ */
+EAPI void
+ecore_x_randr_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ if (mode == Ecore_X_Randr_None) return;
+
+ if (_randr_version >= RANDR_1_3)
+ _ecore_xcb_randr_13_mode_size_get(root, mode, w, h);
+ else if (_randr_version == RANDR_1_2)
+ _ecore_xcb_randr_12_mode_size_get(root, mode, w, h);
+#endif
+}
+
+/**
+ * @brief Gets the EDID information of an attached output if available.
+ * Note that this information is not to be compared using ordinary string
+ * comparison functions, since it includes 0-bytes.
+ *
+ * @param root Window this information should be queried from.
+ * @param output The XID of the output.
+ * @param length Length of the byte-array. If @c NULL, request will fail.
+ * @return EDID information of the output.
+ */
+EAPI unsigned char *
+ecore_x_randr_output_edid_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ unsigned long *length)
+{
+ unsigned char *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_output_property_cookie_t cookie;
+ xcb_randr_get_output_property_reply_t *reply;
+ Ecore_X_Atom atom;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if ((!length) || (!_ecore_xcb_randr_output_validate(root, output)))
+ return NULL;
+
+ atom = ecore_x_atom_get("EDID");
+ cookie =
+ xcb_randr_get_output_property_unchecked(_ecore_xcb_conn, output, atom,
+ XCB_GET_PROPERTY_TYPE_ANY,
+ 0, 100, 0, 0);
+ reply =
+ xcb_randr_get_output_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if ((reply->type == XCB_ATOM_INTEGER) && (reply->format == 8))
+ {
+ if (length) *length = reply->num_items;
+ if ((ret = malloc(reply->num_items * sizeof(unsigned char))))
+ {
+ memcpy(ret, xcb_randr_get_output_property_data(reply),
+ (reply->num_items * sizeof(unsigned char)));
+ }
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+/**
+ * @brief Gets the outputs which might be used simultaneously on the same CRTC.
+ *
+ * @param root Window that this information should be queried for.
+ * @param output The output which's clones we concern.
+ * @param num Number of possible clones.
+ * @return The existing outputs, @c NULL otherwise.
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Output *outputs = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (output == Ecore_X_Randr_None) return NULL;
+
+ if (_randr_version >= RANDR_1_3)
+ outputs = _ecore_xcb_randr_13_output_clones_get(root, output, num);
+ else if (_randr_version == RANDR_1_2)
+ outputs = _ecore_xcb_randr_12_output_clones_get(root, output, num);
+#endif
+ return outputs;
+}
+
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Crtc *crtcs = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (output == Ecore_X_Randr_None) return NULL;
+
+ if (_randr_version >= RANDR_1_3)
+ crtcs = _ecore_xcb_randr_13_output_possible_crtcs_get(root, output, num);
+ else if (_randr_version == RANDR_1_2)
+ crtcs = _ecore_xcb_randr_12_output_possible_crtcs_get(root, output, num);
+#endif
+ return crtcs;
+}
+
+/**
+ * @brief gets the given output's name as reported by X
+ * @param root the window which's screen will be queried
+ * @param output The output name given to be reported.
+ * @param len length of returned c-string.
+ * @return name of the output as reported by X
+ */
+EAPI char *
+ecore_x_randr_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (output == Ecore_X_Randr_None) return NULL;
+
+ if (_randr_version >= RANDR_1_3)
+ return _ecore_xcb_randr_13_output_name_get(root, output, len);
+ else if (_randr_version == RANDR_1_2)
+ return _ecore_xcb_randr_12_output_name_get(root, output, len);
+#endif
+
+ return NULL;
+}
+
+EAPI Ecore_X_Randr_Connection_Status
+ecore_x_randr_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN);
+
+ if (output == Ecore_X_Randr_None)
+ return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+
+ if (_randr_version >= RANDR_1_3)
+ return _ecore_xcb_randr_13_output_connection_status_get(root, output);
+ else if (_randr_version == RANDR_1_2)
+ return _ecore_xcb_randr_12_output_connection_status_get(root, output);
+#endif
+
+ return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+}
+
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_outputs_get(Ecore_X_Window root,
+ int *num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (_randr_version >= RANDR_1_3)
+ return _ecore_xcb_randr_13_outputs_get(root, num);
+ else if (_randr_version == RANDR_1_2)
+ return _ecore_xcb_randr_12_outputs_get(root, num);
+#endif
+
+ return NULL;
+}
+
+EAPI Ecore_X_Randr_Crtc
+ecore_x_randr_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+
+ if (output == Ecore_X_Randr_None) return Ecore_X_Randr_None;
+
+ if (_randr_version >= RANDR_1_3)
+ return _ecore_xcb_randr_13_output_crtc_get(root, output);
+ else if (_randr_version == RANDR_1_2)
+ return _ecore_xcb_randr_12_output_crtc_get(root, output);
+#endif
+
+ return Ecore_X_Randr_None;
+}
+
+EAPI void
+ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w_mm, int *h_mm)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+ xcb_timestamp_t timestamp = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (w_mm) *w_mm = 0;
+ if (h_mm) *h_mm = 0;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ if ((output != Ecore_X_Randr_None) && (_randr_version >= RANDR_1_3))
+ {
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ timestamp = reply->config_timestamp;
+ free(reply);
+ }
+ else if ((output != Ecore_X_Randr_None) && (_randr_version == RANDR_1_2))
+ {
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ timestamp = reply->config_timestamp;
+ free(reply);
+ }
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ if (w_mm) *w_mm = oreply->mm_width;
+ if (h_mm) *h_mm = oreply->mm_height;
+ free(oreply);
+ }
+#endif
+}
+
+/**
+ * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is
+ * auto enabled in it's preferred mode, when it was disabled before.
+ *
+ * @param root The root window which's default display will be queried.
+ * @param crtc The CRTC which's configuration should be altered.
+ * @param outputs An array of outputs, that should display this CRTC's content.
+ * @param noutputs Number of outputs in the array of outputs. If set to
+ * Ecore_X_Randr_Unset, current outputs and number of outputs will be used. If
+ * set to Ecore_X_Randr_None, CRTC will be disabled.
+ * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x
+ * coordinate will be assumed.
+ * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y
+ * coordinate will be assumed.
+ * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the
+ * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is
+ * assumed.
+ * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is
+ * used, the current mode is assumed.
+ * @return @c EINA_TRUE if the configuration alteration was successful,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_settings_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Output *outputs,
+ int noutputs,
+ int x,
+ int y,
+ Ecore_X_Randr_Mode mode,
+ Ecore_X_Randr_Orientation orientation)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ccookie;
+ xcb_randr_get_crtc_info_reply_t *creply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ccookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ creply =
+ xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ccookie, NULL);
+ if (creply)
+ {
+ xcb_randr_set_crtc_config_cookie_t scookie;
+ xcb_randr_set_crtc_config_reply_t *sreply;
+
+ if ((mode == Ecore_X_Randr_None) ||
+ (noutputs == Ecore_X_Randr_None))
+ {
+ outputs = NULL;
+ noutputs = 0;
+ }
+ else if (noutputs == (int)Ecore_X_Randr_Unset)
+ {
+ outputs = xcb_randr_get_crtc_info_outputs(creply);
+ noutputs = creply->num_outputs;
+ }
+ if ((int)mode == Ecore_X_Randr_Unset) mode = creply->mode;
+ if (x < 0) x = creply->x;
+ if (y < 0) y = creply->y;
+ if ((int)orientation == Ecore_X_Randr_Unset)
+ orientation = creply->rotation;
+
+ scookie =
+ xcb_randr_set_crtc_config_unchecked(_ecore_xcb_conn,
+ crtc, XCB_CURRENT_TIME, stamp,
+ x, y, mode, orientation,
+ noutputs, outputs);
+ sreply =
+ xcb_randr_set_crtc_config_reply(_ecore_xcb_conn, scookie, NULL);
+ if (sreply)
+ {
+ ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ?
+ EINA_TRUE : EINA_FALSE;
+ free(sreply);
+ }
+ free(creply);
+ }
+#endif
+
+ return ret;
+}
+
+/**
+ * @brief Sets a mode for a CRTC and the outputs attached to it.
+ *
+ * @param root The window's screen to be queried
+ * @param crtc The CRTC which shall be set
+ * @param outputs Array of outputs which have to be compatible with the mode. If
+ * @c NULL CRTC will be disabled.
+ * @param noutputs Number of outputs in array to be used. Use
+ * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs.
+ * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be
+ * disabled. If set to @c -1 the call will fail.
+ * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_mode_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Output *outputs,
+ int noutputs,
+ Ecore_X_Randr_Mode mode)
+{
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((int)mode == Ecore_X_Randr_Unset) return ret;
+ ret =
+ ecore_x_randr_crtc_settings_set(root, crtc, outputs, noutputs,
+ Ecore_X_Randr_Unset, Ecore_X_Randr_Unset,
+ mode, Ecore_X_Randr_Unset);
+#endif
+
+ return ret;
+}
+
+/**
+ * @brief Get the current set mode of a given CRTC
+ * @param root the window's screen to be queried
+ * @param crtc the CRTC which's should be queried
+ * @return currently set mode or - in case parameters are invalid -
+ * Ecore_X_Randr_Unset
+ */
+EAPI Ecore_X_Randr_Mode
+ecore_x_randr_crtc_mode_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+ Ecore_X_Randr_Mode ret = Ecore_X_Randr_Unset;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_Unset);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->mode;
+ free(oreply);
+ }
+#endif
+
+ return ret;
+}
+
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_crtc_orientation_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+ Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->rotation;
+ free(oreply);
+ }
+#endif
+
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_crtc_orientation_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Orientation orientation)
+{
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (orientation != Ecore_X_Randr_None)
+ {
+ ret =
+ ecore_x_randr_crtc_settings_set(root, crtc, NULL,
+ Ecore_X_Randr_Unset, Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset, Ecore_X_Randr_Unset,
+ orientation);
+ }
+#endif
+ return ret;
+}
+
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_crtc_orientations_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+ Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply =
+ xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->rotations;
+ free(oreply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @brief get a CRTC's possible outputs.
+ * @param root the root window which's screen will be queried
+ * @param num number of possible outputs referenced by given CRTC
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *num)
+{
+ Ecore_X_Randr_Output *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_possible_outputs;
+ ret = malloc(sizeof(Ecore_X_Randr_Output) *
+ oreply->num_possible_outputs);
+ if (ret)
+ {
+ memcpy(ret, xcb_randr_get_crtc_info_possible(oreply),
+ sizeof(Ecore_X_Randr_Output) *
+ oreply->num_possible_outputs);
+ }
+ free(oreply);
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @brief get all known CRTCs related to a root window's screen
+ * @param root window which's screen's ressources are queried
+ * @param num number of CRTCs returned
+ * @return CRTC IDs
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_crtcs_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Crtc *ret = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (_randr_version >= RANDR_1_3)
+ {
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_crtcs;
+ ret = malloc(sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs);
+ if (ret)
+ memcpy(ret, xcb_randr_get_screen_resources_current_crtcs(reply),
+ sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs);
+ free(reply);
+ }
+ }
+ else if (_randr_version == RANDR_1_2)
+ {
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_crtcs;
+ ret = malloc(sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs);
+ if (ret)
+ memcpy(ret, xcb_randr_get_screen_resources_crtcs(reply),
+ sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs);
+ free(reply);
+ }
+ }
+#endif
+
+ return ret;
+}
+
+/*
+ * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead.
+ * @brief Get the CRTCs, which display a certain window.
+ *
+ * @param window Window the displaying CRTCs shall be found for.
+ * @param num The number of CRTCs displaying the window.
+ * @return Array of CRTCs that display a certain window. @c NULL if no CRTCs
+ * was found that displays the specified window.
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_current_crtc_get(Ecore_X_Window window,
+ int *num)
+{
+ return ecore_x_randr_window_crtcs_get(window, num);
+}
+
+/*
+ * @brief Get the CRTCs, which display a certain window.
+ *
+ * @param window Window the displaying crtcs shall be found for.
+ * @param num The number of crtcs displaying the window.
+ * @return Array of crtcs that display a certain window. @c NULL if no crtcs
+ * was found that displays the specified window.
+ * @since 1.2.0
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_window_crtcs_get(Ecore_X_Window window,
+ int *num)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Window root;
+ Eina_Rectangle w_geo, c_geo;
+ Ecore_X_Randr_Crtc *crtcs, *ret = NULL;
+ Ecore_X_Randr_Mode mode;
+ int ncrtcs, i, nret = 0;
+ xcb_translate_coordinates_cookie_t cookie;
+ xcb_translate_coordinates_reply_t *trans;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ ecore_x_window_geometry_get(window, &w_geo.x, &w_geo.y, &w_geo.w, &w_geo.h);
+
+ root = ecore_x_window_root_get(window);
+ crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs);
+ if (!crtcs) goto _ecore_x_randr_window_crtcs_get_fail;
+
+ /* now get window RELATIVE to root window - thats what matters. */
+ cookie = xcb_translate_coordinates(_ecore_xcb_conn, window, root, 0, 0);
+ trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
+ w_geo.x = trans->dst_x;
+ w_geo.y = trans->dst_y;
+ free(trans);
+
+ ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc));
+ if (!ret)
+ {
+ free(crtcs);
+ goto _ecore_x_randr_window_crtcs_get_fail;
+ }
+ for (i = 0, nret = 0; i < ncrtcs; i++)
+ {
+ /* if crtc is not enabled, don't bother about it any further */
+ mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]);
+ if (mode == Ecore_X_Randr_None) continue;
+
+ ecore_x_randr_crtc_geometry_get(root, crtcs[i], &c_geo.x, &c_geo.y,
+ &c_geo.w, &c_geo.h);
+ if (eina_rectangles_intersect(&w_geo, &c_geo))
+ {
+ ret[nret] = crtcs[i];
+ nret++;
+ }
+ }
+ free(crtcs);
+
+ if (num) *num = nret;
+ return ret;
+
+_ecore_x_randr_window_crtcs_get_fail:
+#endif
+ if (num) *num = 0;
+ return NULL;
+}
+
+/*
+ * @brief get a CRTC's outputs.
+ * @param root the root window which's screen will be queried
+ * @param num number of outputs referenced by given CRTC
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_crtc_outputs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *num)
+{
+ Ecore_X_Randr_Output *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(NULL);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_outputs;
+ ret = malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_outputs);
+ if (ret)
+ memcpy(ret, xcb_randr_get_crtc_info_outputs(oreply),
+ sizeof(Ecore_X_Randr_Output) * oreply->num_outputs);
+ free(oreply);
+ }
+#endif
+
+ return ret;
+}
+
+EAPI void
+ecore_x_randr_crtc_geometry_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ if (x) *x = oreply->x;
+ if (y) *y = oreply->y;
+ if (w) *w = oreply->width;
+ if (h) *h = oreply->height;
+ free(oreply);
+ }
+#endif
+}
+
+/**
+ * @brief Sets a CRTC relative to another one.
+ *
+ * @param root The window on which CRTC's position will be set.
+ * @param crtc_r1 The CRTC to be positioned.
+ * @param crtc_r2 The CRTC the position should be relative to.
+ * @param policy The relation between the crtcs.
+ * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at
+ * CRTC2's borders.
+ * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE
+ * if repositioning failed or if position of new crtc would be out of given
+ * screen's min/max bounds.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc_r1,
+ Ecore_X_Randr_Crtc crtc_r2,
+ Ecore_X_Randr_Output_Policy policy,
+ Ecore_X_Randr_Relative_Alignment alignment)
+{
+#ifdef ECORE_XCB_RANDR
+ Eina_Rectangle r1, r2;
+ int w_max = 0, h_max = 0, cw = 0, ch = 0, xn = -1, yn = -1;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((ecore_x_randr_crtc_mode_get(root, crtc_r1) == 0) ||
+ (ecore_x_randr_crtc_mode_get(root, crtc_r2) == 0))
+ return EINA_FALSE;
+
+ if ((!_ecore_xcb_randr_crtc_validate(root, crtc_r1) ||
+ (!(crtc_r1 != crtc_r2) && (!_ecore_xcb_randr_crtc_validate(root, crtc_r2)))))
+ return EINA_FALSE;
+
+ ecore_x_randr_crtc_geometry_get(root, crtc_r1, &r1.x, &r1.y, &r1.w, &r1.h);
+ ecore_x_randr_crtc_geometry_get(root, crtc_r2, &r2.x, &r2.y, &r2.w, &r2.h);
+ ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max);
+ ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
+
+ switch (policy)
+ {
+ case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
+ xn = (r2.x + r2.w);
+ if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE)
+ yn = -1;
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL)
+ yn = ((int)(((double)r2.h / 2.0) + (double)r2.y - ((double)r1.h / 2.0)));
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR)
+ yn = ((int)((double)ch / 2.0) - ((double)r1.h / 2.0));
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
+ xn = (r2.x - r1.w);
+ if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE)
+ yn = -1;
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL)
+ yn = ((int)(((double)r2.h / 2.0) + (double)r2.y - ((double)r1.h / 2.0)));
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR)
+ yn = ((int)((double)ch / 2.0) - ((double)r1.h / 2.0));
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
+ yn = (r2.y + r2.h);
+ if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE)
+ xn = -1;
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL)
+ xn = ((int)((((double)r2.x + (double)r2.w) / 2.0) - ((double)r1.w / 2.0)));
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR)
+ xn = ((int)((double)cw / 2.0));
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
+ yn = (r2.y - r1.h);
+ if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE)
+ xn = -1;
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL)
+ xn = ((int)((((double)r2.x + (double)r2.w) / 2.0) - ((double)r1.w / 2.0)));
+ else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR)
+ xn = ((int)((double)cw / 2.0));
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
+ return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2.x, r2.y);
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
+ break;
+ default:
+ return EINA_FALSE;
+ }
+
+ if ((xn == r1.x) && (yn == r1.x)) return EINA_TRUE;
+ if (((yn + r1.h) > h_max) || ((xn + r1.w) > w_max))
+ return EINA_FALSE;
+
+ return ecore_x_randr_crtc_pos_set(root, crtc_r1, xn, yn);
+#endif
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root,
+ const Ecore_X_Randr_Crtc *not_moved,
+ int num,
+ int dx,
+ int dy)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Randr_Crtc *crtcs = NULL, *move = NULL;
+ int i = 0, j = 0, k = 0, n = 0, total = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if ((num <= 0) || (!not_moved) || (!_ecore_xcb_randr_root_validate(root)))
+ return EINA_FALSE;
+
+ crtcs = ecore_x_randr_crtcs_get(root, &total);
+ n = (total - num);
+ move = malloc(sizeof(Ecore_X_Randr_Crtc) * n);
+ if (move)
+ {
+ for (i = 0, k = 0; (i < total) && (k < n); i++)
+ {
+ for (j = 0; j < num; j++)
+ if (crtcs[i] == not_moved[j]) break;
+ if (j == num)
+ move[k++] = crtcs[i];
+ }
+ ret = ecore_x_randr_move_crtcs(root, move, n, dx, dy);
+ free(move);
+ free(crtcs);
+ }
+#endif
+
+ return ret;
+}
+
+EAPI void
+ecore_x_randr_crtc_pos_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *x,
+ int *y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL);
+#endif
+}
+
+/*
+ * @brief Sets the position of given CRTC within root window's screen.
+ *
+ * @param root The window's screen to be queried.
+ * @param crtc The CRTC which's position within the mentioned screen is to be
+ * altered.
+ * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current
+ * value will be kept.
+ * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current
+ * value will be kept.
+ * @return @c EINA_TRUE if position could be successfully be altered.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_pos_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int x,
+ int y)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RANDR
+ int w = 0, h = 0, nw = 0, nh = 0;
+ Eina_Rectangle rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ ecore_x_randr_crtc_geometry_get(root, crtc,
+ &rect.x, &rect.y, &rect.w, &rect.h);
+ ecore_x_randr_screen_current_size_get(root, &w, &h, NULL, NULL);
+ if (x < 0) x = rect.x;
+ if (y < 0) y = rect.y;
+ if ((x + rect.w) > w)
+ nw = (x + rect.w);
+ if ((y + rect.h) > h)
+ nh = (y + rect.h);
+
+ if ((nw != 0) || (nh != 0))
+ {
+ if (!ecore_x_randr_screen_current_size_set(root, nw, nh, 0, 0))
+ return EINA_FALSE;
+ }
+
+ ret = ecore_x_randr_crtc_settings_set(root, crtc, NULL, -1, x, y, -1, -1);
+#endif
+
+ return ret;
+}
+
+EAPI void
+ecore_x_randr_crtc_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+ ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h);
+#endif
+}
+
+EAPI Ecore_X_Randr_Refresh_Rate
+ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Mode mode)
+{
+ Ecore_X_Randr_Refresh_Rate ret = 0.0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(0.0);
+
+ if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return 0.0;
+
+ if (_randr_version >= RANDR_1_3)
+ {
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+
+ miter =
+ xcb_randr_get_screen_resources_current_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ if (minfo->id == mode)
+ {
+ if ((minfo->htotal) && (minfo->vtotal))
+ {
+ ret = ((double)minfo->dot_clock /
+ ((double)minfo->htotal *
+ (double)minfo->vtotal));
+ }
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ free(reply);
+ }
+ }
+ else if (_randr_version == RANDR_1_2)
+ {
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+
+ miter = xcb_randr_get_screen_resources_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ if (minfo->id == mode)
+ {
+ if ((minfo->htotal) && (minfo->vtotal))
+ {
+ ret = ((double)minfo->dot_clock /
+ ((double)minfo->htotal *
+ (double)minfo->vtotal));
+ }
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ free(reply);
+ }
+ }
+#endif
+ return ret;
+}
+
+/*
+ * @brief Move given CRTCs belonging to the given root window's screen dx/dy
+ * pixels relative to their current position. The screen size will be
+ * automatically adjusted if necessary and possible.
+ *
+ * @param root Window which's screen's resources are used.
+ * @param crtcs List of CRTCs to be moved.
+ * @param ncrtc Number of CRTCs in array.
+ * @param dx Amount of pixels the CRTCs should be moved in x direction.
+ * @param dy Amount of pixels the CRTCs should be moved in y direction.
+ * @return @c EINA_TRUE if all crtcs could be moved successfully.
+ */
+EAPI Eina_Bool
+ecore_x_randr_move_crtcs(Ecore_X_Window root,
+ const Ecore_X_Randr_Crtc *crtcs,
+ int num,
+ int dx,
+ int dy)
+{
+ Eina_Bool ret = EINA_TRUE;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_crtc_info_reply_t *oreply[num];
+ int i = 0, cw = 0, ch = 0;
+ int mw = 0, mh = 0, nw = 0, nh = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (!_ecore_xcb_randr_root_validate(root)) return EINA_FALSE;
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh);
+ ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
+ nw = cw;
+ nh = ch;
+
+ for (i = 0; i < num; i++)
+ {
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtcs[i],
+ stamp);
+ oreply[i] = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply[i])
+ {
+ if (((oreply[i]->x + dx) < 0) ||
+ ((oreply[i]->y + dy) < 0) ||
+ ((oreply[i]->x + oreply[i]->width + dx) > mw) ||
+ ((oreply[i]->y + oreply[i]->height + dy) > mh))
+ {
+ continue;
+ }
+ nw = MAX((int)(oreply[i]->x + oreply[i]->width + dx), nw);
+ nh = MAX((int)(oreply[i]->y + oreply[i]->height + dy), nh);
+ }
+ }
+
+ if ((nw > cw) || (nh > ch))
+ {
+ if (!ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1))
+ {
+ for (i = 0; i < num; i++)
+ if (oreply[i]) free(oreply[i]);
+
+ return EINA_FALSE;
+ }
+ }
+
+ for (i = 0; ((i < num) && (oreply[i])); i++)
+ {
+ if (!oreply[i]) continue;
+ if (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1,
+ (oreply[i]->x + dx),
+ (oreply[i]->y + dy),
+ oreply[i]->mode,
+ oreply[i]->rotation))
+ {
+ ret = EINA_FALSE;
+ break;
+ }
+ }
+
+ if (i < num)
+ {
+ while (i-- >= 0)
+ {
+ if (oreply[i])
+ ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1,
+ (oreply[i]->x - dx),
+ (oreply[i]->y - dy),
+ oreply[i]->mode,
+ oreply[i]->rotation);
+ }
+ }
+
+ for (i = 0; i < num; i++)
+ if (oreply[i]) free(oreply[i]);
+#endif
+
+ return ret;
+}
+
+/**
+ * @brief enable event selection. This enables basic interaction with
+ * output/crtc events and requires RRandR >= 1.2.
+ * @param win select this window's properties for RandRR events
+ * @param on enable/disable selecting
+ */
+EAPI void
+ecore_x_randr_events_select(Ecore_X_Window win,
+ Eina_Bool on)
+{
+#ifdef ECORE_XCB_RANDR
+ uint16_t mask = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (on)
+ {
+ mask = XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE;
+ if (_randr_version >= ((1 << 16) | 2))
+ {
+ mask |= (XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
+ }
+ }
+
+ xcb_randr_select_input(_ecore_xcb_conn, win, mask);
+#endif
+}
+
+/**
+ * @brief removes unused screen space. The most upper left CRTC is set to 0x0
+ * and all other CRTCs dx,dy respectively.
+ * @param root the window's screen which will be reset.
+ */
+EAPI void
+ecore_x_randr_screen_reset(Ecore_X_Window root)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ Ecore_X_Randr_Crtc *crtcs = NULL;
+ int total = 0, i = 0, w = 0, h = 0;
+ int dx = 100000, dy = 100000, num = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ if (!_ecore_xcb_randr_root_validate(root)) return;
+ crtcs = ecore_x_randr_crtcs_get(root, &total);
+
+ if (_randr_version >= RANDR_1_3)
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+ else if (_randr_version == RANDR_1_2)
+ stamp = _ecore_xcb_randr_12_get_resource_timestamp(root);
+
+ /* I hate declaring variables inside code like this, but we need the
+ * value of 'total' before we can */
+ Ecore_X_Randr_Crtc enabled[total];
+
+ for (i = 0; i < total; i++)
+ {
+ xcb_randr_get_crtc_info_cookie_t ocookie;
+ xcb_randr_get_crtc_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtcs[i], stamp);
+ oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (!oreply) continue;
+ if ((oreply->mode <= 0) || (oreply->num_outputs == 0))
+ {
+ free(oreply);
+ continue;
+ }
+
+ enabled[num++] = crtcs[i];
+ if ((int)(oreply->x + oreply->width) > w)
+ w = (oreply->x + oreply->width);
+ if ((int)(oreply->y + oreply->height) > h)
+ h = (oreply->y + oreply->height);
+
+ if (oreply->x < dx) dx = oreply->x;
+ if (oreply->y < dy) dy = oreply->y;
+
+ free(oreply);
+ }
+ free(crtcs);
+
+ if ((dx > 0) || (dy > 0))
+ {
+ if (ecore_x_randr_move_crtcs(root, enabled, num, -dx, -dy))
+ {
+ w -= dx;
+ h -= dy;
+ }
+ }
+
+ ecore_x_randr_screen_current_size_set(root, w, h, -1, -1);
+#endif
+}
+
+/*
+ * @param root window which's screen will be queried
+ * @param wmin minimum width the screen can be set to
+ * @param hmin minimum height the screen can be set to
+ * @param wmax maximum width the screen can be set to
+ * @param hmax maximum height the screen can be set to
+ */
+EAPI void
+ecore_x_randr_screen_size_range_get(Ecore_X_Window root,
+ int *minw,
+ int *minh,
+ int *maxw,
+ int *maxh)
+{
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_size_range_cookie_t cookie;
+ xcb_randr_get_screen_size_range_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ cookie = xcb_randr_get_screen_size_range_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_randr_get_screen_size_range_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if (minw) *minw = reply->min_width;
+ if (minh) *minh = reply->min_height;
+ if (maxw) *maxw = reply->max_width;
+ if (maxh) *maxh = reply->max_height;
+ free(reply);
+ }
+#endif
+}
+
+/*
+ * @param w width of screen in px
+ * @param h height of screen in px
+ */
+EAPI void
+ecore_x_randr_screen_current_size_get(Ecore_X_Window root,
+ int *w,
+ int *h,
+ int *w_mm,
+ int *h_mm)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Randr_Screen scr = 0;
+ xcb_screen_t *s;
+# define RANDR_VALIDATE_ROOT(screen, root) \
+ ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1)
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET();
+
+ if (!RANDR_VALIDATE_ROOT(scr, root)) return;
+
+ s = ecore_x_screen_get(scr);
+ if (w) *w = s->width_in_pixels;
+ if (h) *h = s->height_in_pixels;
+ if (w_mm) *w_mm = s->width_in_millimeters;
+ if (h_mm) *h_mm = s->height_in_millimeters;
+#endif
+}
+
+/*
+ * @param root Window which's screen's size should be set. If invalid (e.g.
+ * @c NULL) no action is taken.
+ * @param w Width in px the screen should be set to. If out of valid
+ * boundaries, current value is assumed.
+ * @param h Height in px the screen should be set to. If out of valid
+ * boundaries, current value is assumed.
+ * @param w_mm Width in mm the screen should be set to. If @c 0, current
+ * aspect is assumed.
+ * @param h_mm Height in mm the screen should be set to. If @c 0, current
+ * aspect is assumed.
+ * @return @c EINA_TRUE if request was successfully sent or screen is already
+ * in requested size, @c EINA_FALSE if parameters are invalid.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_current_size_set(Ecore_X_Window root,
+ int w,
+ int h,
+ int w_mm,
+ int h_mm)
+{
+ Eina_Bool ret = EINA_TRUE;
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Randr_Screen scr;
+ int wc = 0, hc = 0, w_mm_c = 0, h_mm_c = 0;
+ int mw = 0, mh = 0, xw = 0, xh = 0;
+# define RANDR_VALIDATE_ROOT(screen, root) \
+ ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1)
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (!RANDR_VALIDATE_ROOT(scr, root)) return EINA_FALSE;
+ ecore_x_randr_screen_current_size_get(root, &wc, &hc, &w_mm_c, &h_mm_c);
+ if ((w == wc) && (h == hc) && (w_mm == w_mm_c) && (h_mm == h_mm_c))
+ return EINA_TRUE;
+ ecore_x_randr_screen_size_range_get(root, &mw, &mh, &xw, &xh);
+ if (((w != 1) && ((w < mw) || (w > xw))) ||
+ ((h != -1) && ((h < mh) || (h > xh)))) return EINA_FALSE;
+
+ if (w <= 0)
+ w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels;
+ if (h <= 0)
+ h = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels;
+
+ /* NB: Hmmmm, xlib version divides w_mm by width ... that seems wrong */
+ if (w_mm <= 0)
+ w_mm = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_millimeters;
+ if (h_mm <= 0)
+ h_mm = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_millimeters;
+
+ xcb_randr_set_screen_size(_ecore_xcb_conn, root, w, h, w_mm, h_mm);
+#endif
+
+ return ret;
+}
+
+/*
+ * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead.
+ * @brief Get the outputs, which display a certain window.
+ *
+ * @param window Window the displaying outputs shall be found for.
+ * @param num The number of outputs displaying the window.
+ * @return Array of outputs that display a certain window. @c NULL if no
+ * outputs was found that displays the specified window.
+ */
+
+Ecore_X_Randr_Output *
+ecore_x_randr_current_output_get(Ecore_X_Window window,
+ int *num)
+{
+ return ecore_x_randr_window_outputs_get(window, num);
+}
+
+/*
+ * @brief Get the outputs, which display a certain window.
+ *
+ * @param window Window the displaying outputs shall be found for.
+ * @param num The number of outputs displaying the window.
+ * @return Array of outputs that display a certain window. @c NULL if no
+ * outputs was found that displays the specified window.
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_window_outputs_get(Ecore_X_Window window,
+ int *num)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Window root;
+ Ecore_X_Randr_Crtc *crtcs;
+ Ecore_X_Randr_Output *outputs, *ret = NULL, *tret;
+ int ncrtcs, noutputs, i, nret = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+
+#ifdef ECORE_XCB_RANDR
+ if (_randr_version < RANDR_1_2) goto _ecore_x_randr_current_output_get_fail;
+
+ root = ecore_x_window_root_get(window);
+ if (!(crtcs = ecore_x_randr_window_crtcs_get(window, &ncrtcs)))
+ goto _ecore_x_randr_current_output_get_fail;
+
+ for (i = 0, nret = 0; i < ncrtcs; i++)
+ {
+
+ outputs = ecore_x_randr_crtc_outputs_get(root, crtcs[i],
+ &noutputs);
+ if (!outputs)
+ goto _ecore_x_randr_current_output_get_fail_free;
+ tret = realloc(ret, ((nret + noutputs) * sizeof(Ecore_X_Randr_Output)));
+ if (!tret) goto _ecore_x_randr_current_output_get_fail_free;
+ ret = tret;
+ memcpy(&ret[nret], outputs, (noutputs * sizeof(Ecore_X_Randr_Output)));
+ nret += noutputs;
+ free(outputs);
+ outputs = NULL;
+ }
+ free(crtcs);
+
+ if (num)
+ *num = nret;
+
+ return ret;
+
+_ecore_x_randr_current_output_get_fail_free:
+ free(outputs);
+ free(crtcs);
+ free(ret);
+_ecore_x_randr_current_output_get_fail:
+#endif
+ if (num) *num = 0;
+ return NULL;
+}
+
+/*
+ * @brief get the backlight level of the given output
+ * @param root window which's screen should be queried
+ * @param output from which the backlight level should be retrieved
+ * @return the backlight level
+ */
+EAPI double
+ecore_x_randr_output_backlight_level_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Atom _backlight;
+ xcb_intern_atom_cookie_t acookie;
+ xcb_intern_atom_reply_t *areply;
+ xcb_randr_get_output_property_cookie_t cookie;
+ xcb_randr_get_output_property_reply_t *reply;
+ xcb_randr_query_output_property_cookie_t qcookie;
+ xcb_randr_query_output_property_reply_t *qreply;
+ double dvalue;
+ long value, max, min;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(-1);
+
+ acookie =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 1,
+ strlen("Backlight"), "Backlight");
+ areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL);
+
+ if (!areply)
+ {
+ ERR("Backlight property is not suppported on this server or driver");
+ return -1;
+ }
+ else
+ {
+ _backlight = areply->atom;
+ free(areply);
+ }
+
+ if (!_ecore_xcb_randr_output_validate(root, output))
+ {
+ ERR("Invalid output");
+ return -1;
+ }
+
+ cookie =
+ xcb_randr_get_output_property_unchecked(_ecore_xcb_conn,
+ output, _backlight,
+ XCB_ATOM_NONE, 0, 4, 0, 0);
+ reply =
+ xcb_randr_get_output_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply)
+ {
+ WRN("Backlight not supported on this output");
+ return -1;
+ }
+
+ if ((reply->format != 32) || (reply->num_items != 1) ||
+ (reply->type != XCB_ATOM_INTEGER))
+ {
+ free(reply);
+ return -1;
+ }
+
+ value = *((long *)xcb_randr_get_output_property_data(reply));
+ free (reply);
+
+ /* I have the current value of the backlight */
+ /* Now retrieve the min and max intensities of the output */
+ qcookie =
+ xcb_randr_query_output_property_unchecked(_ecore_xcb_conn,
+ output, _backlight);
+ qreply =
+ xcb_randr_query_output_property_reply(_ecore_xcb_conn, qcookie, NULL);
+ if (qreply)
+ {
+ dvalue = -1;
+ if ((qreply->range) &&
+ (xcb_randr_query_output_property_valid_values_length(qreply) == 2))
+ {
+ int32_t *vals;
+
+ vals = xcb_randr_query_output_property_valid_values(qreply);
+ /* finally convert the current value in the interval [0..1] */
+ min = vals[0];
+ max = vals[1];
+ dvalue = ((double)(value - min)) / ((double)(max - min));
+ }
+ free(qreply);
+ return dvalue;
+ }
+#endif
+ return -1;
+}
+
+/*
+ * @brief Set the backlight level of a given output.
+ *
+ * @param root Window which's screen should be queried.
+ * @param output That should be set.
+ * @param level For which the backlight should be set.
+ * @return @c EINA_TRUE in case of success.
+ */
+EAPI Eina_Bool
+ecore_x_randr_output_backlight_level_set(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ double level)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Atom _backlight;
+ xcb_intern_atom_cookie_t acookie;
+ xcb_intern_atom_reply_t *areply;
+ xcb_randr_query_output_property_cookie_t qcookie;
+ xcb_randr_query_output_property_reply_t *qreply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((level < 0) || (level > 1))
+ {
+ ERR("Backlight level should be between 0 and 1");
+ return EINA_FALSE;
+ }
+
+ if (!_ecore_xcb_randr_output_validate(root, output))
+ {
+ ERR("Wrong output value");
+ return EINA_FALSE;
+ }
+
+ acookie =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 1,
+ strlen("Backlight"), "Backlight");
+ areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL);
+ if (!areply)
+ {
+ WRN("Backlight property is not suppported on this server or driver");
+ return EINA_FALSE;
+ }
+ else
+ {
+ _backlight = areply->atom;
+ free(areply);
+ }
+
+ qcookie =
+ xcb_randr_query_output_property_unchecked(_ecore_xcb_conn,
+ output, _backlight);
+ qreply =
+ xcb_randr_query_output_property_reply(_ecore_xcb_conn, qcookie, NULL);
+ if (qreply)
+ {
+ if ((qreply->range) && (qreply->length == 2))
+ {
+ int32_t *vals;
+ double min, max, tmp;
+ long n;
+
+ vals = xcb_randr_query_output_property_valid_values(qreply);
+ min = vals[0];
+ max = vals[1];
+ tmp = (level * (max - min)) + min;
+ n = tmp;
+ if (n > max) n = max;
+ if (n < min) n = min;
+ xcb_randr_change_output_property(_ecore_xcb_conn, output,
+ _backlight, XCB_ATOM_INTEGER,
+ 32, XCB_PROP_MODE_REPLACE,
+ 1, (unsigned char *)&n);
+ ecore_x_flush(); // needed
+ }
+
+ free(qreply);
+ return EINA_TRUE;
+ }
+#endif
+ return EINA_FALSE;
+}
+
+/*
+ * @brief Check if a backlight is available.
+ *
+ * @return Whether a backlight is available.
+ */
+EAPI Eina_Bool
+ecore_x_randr_output_backlight_available(void)
+{
+#ifdef ECORE_XCB_RANDR
+ Ecore_X_Atom _backlight;
+ xcb_intern_atom_cookie_t acookie;
+ xcb_intern_atom_reply_t *areply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ acookie =
+ xcb_intern_atom_unchecked(_ecore_xcb_conn, 1,
+ strlen("Backlight"), "Backlight");
+ areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL);
+
+ if (!areply)
+ {
+ ERR("Backlight property is not suppported on this server or driver");
+ return EINA_FALSE;
+ }
+ else
+ {
+ _backlight = areply->atom;
+ free(areply);
+ return EINA_TRUE;
+ }
+#endif
+ return EINA_FALSE;
+}
+
+EAPI int
+ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length)
+{
+ if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) &&
+ (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
+ return (edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) |
+ edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR];
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+}
+
+EAPI char *
+ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length)
+{
+ unsigned char *block = NULL;
+ int version = 0;
+
+ version = ecore_x_randr_edid_version_get(edid, edid_length);
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
+
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc)
+ {
+ char *name, *p;
+ const char *edid_name;
+
+ edid_name = (const char *)block +
+ _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
+ name =
+ malloc(sizeof(char) *
+ _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
+ if (!name) return NULL;
+
+ strncpy(name, edid_name,
+ (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
+ name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
+ for (p = name; *p; p++)
+ if ((*p < ' ') || (*p > '~')) *p = 0;
+
+ return name;
+ }
+ }
+ return NULL;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length)
+{
+ const unsigned char header[] =
+ {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+ };
+
+ if ((!edid) || (edid_length < 8)) return EINA_FALSE;
+ if (!memcmp(edid, header, 8)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+/* local functions */
+static Eina_Bool
+_ecore_xcb_randr_output_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((output) && (_ecore_xcb_randr_root_validate(root)))
+ {
+ if (_randr_version >= RANDR_1_3)
+ {
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ int len = 0, i = 0;
+ xcb_randr_output_t *outputs;
+
+ len =
+ xcb_randr_get_screen_resources_current_outputs_length(reply);
+ outputs =
+ xcb_randr_get_screen_resources_current_outputs(reply);
+ for (i = 0; i < len; i++)
+ {
+ if (outputs[i] == output)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ free(reply);
+ }
+ }
+ else if (_randr_version == RANDR_1_2)
+ {
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ int len = 0, i = 0;
+ xcb_randr_output_t *outputs;
+
+ len = xcb_randr_get_screen_resources_outputs_length(reply);
+ outputs = xcb_randr_get_screen_resources_outputs(reply);
+ for (i = 0; i < len; i++)
+ {
+ if (outputs[i] == output)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ free(reply);
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+/**
+ * @brief Validates a CRTC for a given root window's screen.
+ *
+ * @param root The window which's default display will be queried.
+ * @param crtc The CRTC to be validated.
+ * @return In case it is found @c EINA_TRUE will be returned, else
+ * @c EINA_FALSE is returned.
+ */
+static Eina_Bool
+_ecore_xcb_randr_crtc_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (((int)crtc == Ecore_X_Randr_None) || ((int)crtc == Ecore_X_Randr_Unset))
+ return ret;
+
+ if ((crtc) && (_ecore_xcb_randr_root_validate(root)))
+ {
+ if (_randr_version >= RANDR_1_3)
+ {
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ int i = 0;
+ xcb_randr_crtc_t *crtcs;
+
+ crtcs = xcb_randr_get_screen_resources_current_crtcs(reply);
+ for (i = 0; i < reply->num_crtcs; i++)
+ {
+ if (crtcs[i] == crtc)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ free(reply);
+ }
+ }
+ else if (_randr_version == RANDR_1_2)
+ {
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ int i = 0;
+ xcb_randr_crtc_t *crtcs;
+
+ crtcs = xcb_randr_get_screen_resources_crtcs(reply);
+ for (i = 0; i < reply->num_crtcs; i++)
+ {
+ if (crtcs[i] == crtc)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ free(reply);
+ }
+ }
+ }
+#endif
+
+ return ret;
+}
+
+static Ecore_X_Randr_Mode *
+_ecore_xcb_randr_12_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred)
+{
+ Ecore_X_Randr_Mode *modes = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_modes;
+ if (npreferred) *npreferred = oreply->num_preferred;
+
+ modes = malloc(sizeof(Ecore_X_Randr_Mode) *
+ oreply->num_modes);
+ if (modes)
+ {
+ xcb_randr_mode_t *rmodes;
+ int len = 0;
+
+ len = xcb_randr_get_output_info_modes_length(oreply);
+ rmodes = xcb_randr_get_output_info_modes(oreply);
+ memcpy(modes, rmodes, sizeof(Ecore_X_Randr_Mode) * len);
+ }
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return modes;
+}
+
+static Ecore_X_Randr_Mode *
+_ecore_xcb_randr_13_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred)
+{
+ Ecore_X_Randr_Mode *modes = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_timestamp_t stamp = 0;
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ stamp = _ecore_xcb_randr_13_get_resource_timestamp(root);
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, stamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_modes;
+ if (npreferred) *npreferred = oreply->num_preferred;
+
+ modes = malloc(sizeof(Ecore_X_Randr_Mode) * oreply->num_modes);
+ if (modes)
+ {
+ xcb_randr_mode_t *rmodes;
+ int len = 0;
+
+ len = xcb_randr_get_output_info_modes_length(oreply);
+ rmodes = xcb_randr_get_output_info_modes(oreply);
+ memcpy(modes, rmodes, sizeof(Ecore_X_Randr_Mode) * len);
+ }
+ free(oreply);
+ }
+#endif
+ return modes;
+}
+
+static Ecore_X_Randr_Mode_Info *
+_ecore_xcb_randr_12_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode)
+{
+ Ecore_X_Randr_Mode_Info *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ if ((ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ uint8_t *nbuf;
+ xcb_randr_mode_info_iterator_t miter;
+
+ nbuf = xcb_randr_get_screen_resources_names(reply);
+ miter = xcb_randr_get_screen_resources_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ nbuf += minfo->name_len;
+
+ if (minfo->id == mode)
+ {
+ ret->xid = minfo->id;
+ ret->width = minfo->width;
+ ret->height = minfo->height;
+ ret->dotClock = minfo->dot_clock;
+ ret->hSyncStart = minfo->hsync_start;
+ ret->hSyncEnd = minfo->hsync_end;
+ ret->hTotal = minfo->htotal;
+ ret->vSyncStart = minfo->vsync_start;
+ ret->vSyncEnd = minfo->vsync_end;
+ ret->vTotal = minfo->vtotal;
+ ret->modeFlags = minfo->mode_flags;
+
+ ret->name = NULL;
+ ret->nameLength = minfo->name_len;
+ if (ret->nameLength > 0)
+ {
+ ret->name = malloc(ret->nameLength + 1);
+ if (ret->name)
+ memcpy(ret->name, nbuf, ret->nameLength + 1);
+ }
+
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ }
+
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Mode_Info *
+_ecore_xcb_randr_13_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode)
+{
+ Ecore_X_Randr_Mode_Info *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ if ((ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ uint8_t *nbuf;
+ xcb_randr_mode_info_iterator_t miter;
+
+ nbuf = xcb_randr_get_screen_resources_current_names(reply);
+ miter =
+ xcb_randr_get_screen_resources_current_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ nbuf += minfo->name_len;
+
+ if (minfo->id == mode)
+ {
+ ret->xid = minfo->id;
+ ret->width = minfo->width;
+ ret->height = minfo->height;
+ ret->dotClock = minfo->dot_clock;
+ ret->hSyncStart = minfo->hsync_start;
+ ret->hSyncEnd = minfo->hsync_end;
+ ret->hTotal = minfo->htotal;
+ ret->vSyncStart = minfo->vsync_start;
+ ret->vSyncEnd = minfo->vsync_end;
+ ret->vTotal = minfo->vtotal;
+ ret->modeFlags = minfo->mode_flags;
+
+ ret->name = NULL;
+ ret->nameLength = minfo->name_len;
+ if (ret->nameLength > 0)
+ {
+ ret->name = malloc(ret->nameLength + 1);
+ if (ret->name)
+ memcpy(ret->name, nbuf, ret->nameLength + 1);
+ }
+
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ }
+
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Mode_Info **
+_ecore_xcb_randr_12_modes_info_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Mode_Info **ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_modes;
+ ret = malloc(sizeof(Ecore_X_Randr_Mode_Info *) * reply->num_modes);
+ if (ret)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+ int i = 0;
+ uint8_t *nbuf;
+
+ nbuf = xcb_randr_get_screen_resources_names(reply);
+ miter = xcb_randr_get_screen_resources_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ nbuf += minfo->name_len;
+ if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ ret[i]->xid = minfo->id;
+ ret[i]->width = minfo->width;
+ ret[i]->height = minfo->height;
+ ret[i]->dotClock = minfo->dot_clock;
+ ret[i]->hSyncStart = minfo->hsync_start;
+ ret[i]->hSyncEnd = minfo->hsync_end;
+ ret[i]->hTotal = minfo->htotal;
+ ret[i]->vSyncStart = minfo->vsync_start;
+ ret[i]->vSyncEnd = minfo->vsync_end;
+ ret[i]->vTotal = minfo->vtotal;
+ ret[i]->modeFlags = minfo->mode_flags;
+
+ ret[i]->name = NULL;
+ ret[i]->nameLength = minfo->name_len;
+ if (ret[i]->nameLength > 0)
+ {
+ ret[i]->name = malloc(ret[i]->nameLength + 1);
+ if (ret[i]->name)
+ memcpy(ret[i]->name, nbuf,
+ ret[i]->nameLength + 1);
+ }
+ }
+ else
+ {
+ while (i > 0)
+ free(ret[--i]);
+ free(ret);
+ ret = NULL;
+ break;
+ }
+ i++;
+ xcb_randr_mode_info_next(&miter);
+ }
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Mode_Info **
+_ecore_xcb_randr_13_modes_info_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Mode_Info **ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_modes;
+ ret = malloc(sizeof(Ecore_X_Randr_Mode_Info *) * reply->num_modes);
+ if (ret)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+ int i = 0;
+ uint8_t *nbuf;
+
+ nbuf = xcb_randr_get_screen_resources_current_names(reply);
+ miter =
+ xcb_randr_get_screen_resources_current_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ nbuf += minfo->name_len;
+ if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ ret[i]->xid = minfo->id;
+ ret[i]->width = minfo->width;
+ ret[i]->height = minfo->height;
+ ret[i]->dotClock = minfo->dot_clock;
+ ret[i]->hSyncStart = minfo->hsync_start;
+ ret[i]->hSyncEnd = minfo->hsync_end;
+ ret[i]->hTotal = minfo->htotal;
+ ret[i]->vSyncStart = minfo->vsync_start;
+ ret[i]->vSyncEnd = minfo->vsync_end;
+ ret[i]->vTotal = minfo->vtotal;
+ ret[i]->modeFlags = minfo->mode_flags;
+
+ ret[i]->name = NULL;
+ ret[i]->nameLength = minfo->name_len;
+ if (ret[i]->nameLength > 0)
+ {
+ ret[i]->name = malloc(ret[i]->nameLength + 1);
+ if (ret[i]->name)
+ memcpy(ret[i]->name, nbuf,
+ ret[i]->nameLength + 1);
+ }
+ }
+ else
+ {
+ while (i > 0)
+ free(ret[--i]);
+ free(ret);
+ ret = NULL;
+ break;
+ }
+ i++;
+ xcb_randr_mode_info_next(&miter);
+ }
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static void
+_ecore_xcb_randr_12_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h)
+{
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+
+ miter = xcb_randr_get_screen_resources_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ if (minfo->id == mode)
+ {
+ if (w) *w = minfo->width;
+ if (h) *h = minfo->height;
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ free(reply);
+ }
+#endif
+}
+
+static void
+_ecore_xcb_randr_13_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h)
+{
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_mode_info_iterator_t miter;
+
+ miter = xcb_randr_get_screen_resources_current_modes_iterator(reply);
+ while (miter.rem)
+ {
+ xcb_randr_mode_info_t *minfo;
+
+ minfo = miter.data;
+ if (minfo->id == mode)
+ {
+ if (w) *w = minfo->width;
+ if (h) *h = minfo->height;
+ break;
+ }
+ xcb_randr_mode_info_next(&miter);
+ }
+ free(reply);
+ }
+#endif
+}
+
+static Ecore_X_Randr_Output *
+_ecore_xcb_randr_12_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Output *outputs = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_clones;
+
+ outputs =
+ malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_clones);
+ if (outputs)
+ {
+ memcpy(outputs, xcb_randr_get_output_info_clones(oreply),
+ sizeof(Ecore_X_Randr_Output) * oreply->num_clones);
+ }
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return outputs;
+}
+
+static Ecore_X_Randr_Output *
+_ecore_xcb_randr_13_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Output *outputs = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_clones;
+
+ outputs =
+ malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_clones);
+ if (outputs)
+ {
+ memcpy(outputs, xcb_randr_get_output_info_clones(oreply),
+ sizeof(Ecore_X_Randr_Output) * oreply->num_clones);
+ }
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return outputs;
+}
+
+static Ecore_X_Randr_Crtc *
+_ecore_xcb_randr_12_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Crtc *crtcs = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_crtcs;
+
+ crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs);
+ if (crtcs)
+ {
+ memcpy(crtcs, xcb_randr_get_output_info_crtcs(oreply),
+ sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs);
+ }
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return crtcs;
+}
+
+static Ecore_X_Randr_Crtc *
+_ecore_xcb_randr_13_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+ Ecore_X_Randr_Crtc *crtcs = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ if (num) *num = oreply->num_crtcs;
+
+ crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs);
+ if (crtcs)
+ {
+ memcpy(crtcs, xcb_randr_get_output_info_crtcs(oreply),
+ sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs);
+ }
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return crtcs;
+}
+
+static char *
+_ecore_xcb_randr_12_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len)
+{
+ char *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ uint8_t *nbuf;
+
+ nbuf = xcb_randr_get_output_info_name(oreply);
+ nbuf += oreply->name_len;
+
+ if (len) *len = oreply->name_len;
+ if (oreply->name_len > 0)
+ {
+ ret = malloc(oreply->name_len + 1);
+ if (ret)
+ memcpy(ret, nbuf, oreply->name_len + 1);
+ }
+
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static char *
+_ecore_xcb_randr_13_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len)
+{
+ char *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ uint8_t *nbuf;
+
+ nbuf = xcb_randr_get_output_info_name(oreply);
+ nbuf += oreply->name_len;
+
+ if (len) *len = oreply->name_len;
+ if (oreply->name_len > 0)
+ {
+ ret = malloc(oreply->name_len + 1);
+ if (ret)
+ memcpy(ret, nbuf, oreply->name_len + 1);
+ }
+
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Connection_Status
+_ecore_xcb_randr_12_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ Ecore_X_Randr_Connection_Status ret = ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->connection;
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Connection_Status
+_ecore_xcb_randr_13_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ Ecore_X_Randr_Connection_Status ret = ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->connection;
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Output *
+_ecore_xcb_randr_12_outputs_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Output *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_outputs;
+ ret = malloc(sizeof(Ecore_X_Randr_Output) * reply->num_outputs);
+ if (ret)
+ memcpy(ret, xcb_randr_get_screen_resources_outputs(reply),
+ sizeof(Ecore_X_Randr_Output) * reply->num_outputs);
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Output *
+_ecore_xcb_randr_13_outputs_get(Ecore_X_Window root,
+ int *num)
+{
+ Ecore_X_Randr_Output *ret = NULL;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ if (num) *num = reply->num_outputs;
+ ret = malloc(sizeof(Ecore_X_Randr_Output) * reply->num_outputs);
+ if (ret)
+ memcpy(ret, xcb_randr_get_screen_resources_current_outputs(reply),
+ sizeof(Ecore_X_Randr_Output) * reply->num_outputs);
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Crtc
+_ecore_xcb_randr_12_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->crtc;
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static Ecore_X_Randr_Crtc
+_ecore_xcb_randr_13_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+ Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(root);
+ if (reply)
+ {
+ xcb_randr_get_output_info_cookie_t ocookie;
+ xcb_randr_get_output_info_reply_t *oreply;
+
+ ocookie =
+ xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output,
+ reply->config_timestamp);
+ oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn,
+ ocookie, NULL);
+ if (oreply)
+ {
+ ret = oreply->crtc;
+ free(oreply);
+ }
+ free(reply);
+ }
+#endif
+ return ret;
+}
+
+static xcb_randr_get_screen_resources_reply_t *
+_ecore_xcb_randr_12_get_resources(Ecore_X_Window win)
+{
+ xcb_randr_get_screen_resources_cookie_t cookie;
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ cookie = xcb_randr_get_screen_resources_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_randr_get_screen_resources_reply(_ecore_xcb_conn, cookie, NULL);
+ return reply;
+}
+
+static xcb_randr_get_screen_resources_current_reply_t *
+_ecore_xcb_randr_13_get_resources(Ecore_X_Window win)
+{
+ xcb_randr_get_screen_resources_current_cookie_t cookie;
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ cookie =
+ xcb_randr_get_screen_resources_current_unchecked(_ecore_xcb_conn, win);
+ reply =
+ xcb_randr_get_screen_resources_current_reply(_ecore_xcb_conn,
+ cookie, NULL);
+ return reply;
+}
+
+static xcb_timestamp_t
+_ecore_xcb_randr_12_get_resource_timestamp(Ecore_X_Window win)
+{
+ xcb_timestamp_t stamp = 0;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_reply_t *reply;
+
+ reply = _ecore_xcb_randr_12_get_resources(win);
+ stamp = reply->config_timestamp;
+ free(reply);
+#endif
+ return stamp;
+}
+
+static xcb_timestamp_t
+_ecore_xcb_randr_13_get_resource_timestamp(Ecore_X_Window win)
+{
+ xcb_timestamp_t stamp = 0;
+#ifdef ECORE_XCB_RANDR
+ xcb_randr_get_screen_resources_current_reply_t *reply;
+
+ reply = _ecore_xcb_randr_13_get_resources(win);
+ stamp = reply->config_timestamp;
+ free(reply);
+#endif
+ return stamp;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_region.c b/src/lib/ecore_x/xcb/ecore_xcb_region.c
new file mode 100644
index 0000000000..a221d8fc37
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_region.c
@@ -0,0 +1,159 @@
+#include "ecore_xcb_private.h"
+#include <pixman.h>
+
+/*
+ * [ ] XPolygonRegion
+ * [ ] XShrinkRegion
+ * [ ] XClipBox
+ * [ ] XXorRegion
+ */
+
+EAPI Ecore_X_XRegion *
+ecore_x_xregion_new()
+{
+ pixman_region16_t *region;
+
+ region = (pixman_region16_t *)malloc(sizeof(pixman_region16_t));
+ if (!region) return NULL;
+
+ pixman_region_init(region);
+
+ return (Ecore_X_XRegion *)region;
+}
+
+EAPI void
+ecore_x_xregion_free(Ecore_X_XRegion *region)
+{
+ if (!region) return;
+
+ pixman_region_fini(region);
+ free(region);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_set(Ecore_X_XRegion *region,
+ Ecore_X_GC gc)
+{
+ xcb_rectangle_t *rects;
+ pixman_box16_t *boxes;
+ int num = 0, i = 0;
+
+ CHECK_XCB_CONN;
+
+ if (!region) return EINA_FALSE;
+
+ boxes = pixman_region_rectangles((pixman_region16_t *)region, &num);
+ if ((!boxes) || (num == 0)) return EINA_FALSE;
+
+ rects = (xcb_rectangle_t *)malloc(sizeof(xcb_rectangle_t) * num);
+ if (!rects) return EINA_FALSE;
+
+ for (i = 0; i < num; i++)
+ {
+ rects[i].x = boxes[i].x1;
+ rects[i].y = boxes[i].y1;
+ rects[i].width = boxes[i].x2 - boxes[i].x1 + 1;
+ rects[i].height = boxes[i].y2 - boxes[i].y1 + 1;
+ }
+
+ xcb_set_clip_rectangles(_ecore_xcb_conn, XCB_CLIP_ORDERING_YX_BANDED,
+ gc, 0, 0, num, rects);
+
+// ecore_x_flush();
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_xregion_translate(Ecore_X_XRegion *region,
+ int x,
+ int y)
+{
+ if (!region) return;
+
+ pixman_region_translate((pixman_region16_t *)region, x, y);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_intersect(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ return pixman_region_intersect((pixman_region16_t *)dst,
+ (pixman_region16_t *)r1,
+ (pixman_region16_t *)r2);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_union(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ return pixman_region_union((pixman_region16_t *)dst,
+ (pixman_region16_t *)r1,
+ (pixman_region16_t *)r2);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_union_rect(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *src,
+ Ecore_X_Rectangle *rect)
+{
+ return pixman_region_union_rect((pixman_region16_t *)dst,
+ (pixman_region16_t *)src,
+ rect->x, rect->y, rect->width, rect->height);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_subtract(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *rm,
+ Ecore_X_XRegion *rs)
+{
+ return pixman_region_subtract((pixman_region16_t *)dst,
+ (pixman_region16_t *)rm,
+ (pixman_region16_t *)rs);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_is_empty(Ecore_X_XRegion *region)
+{
+ if (!region) return EINA_TRUE;
+
+ return !pixman_region_not_empty((pixman_region16_t *)region);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_is_equal(Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ if ((!r1) || (!r2)) return EINA_FALSE;
+
+ return pixman_region_equal((pixman_region16_t *)r1,
+ (pixman_region16_t *)r2);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_point_contain(Ecore_X_XRegion *region,
+ int x,
+ int y)
+{
+ if (!region) return EINA_FALSE;
+
+ return pixman_region_contains_point((pixman_region16_t *)region, x, y, NULL);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_rect_contain(Ecore_X_XRegion *region,
+ Ecore_X_Rectangle *rect)
+{
+ pixman_box16_t box;
+
+ if ((!region) || (!rect)) return EINA_FALSE;
+
+ box.x1 = rect->x;
+ box.y1 = rect->y;
+ box.x2 = rect->x + rect->width - 1;
+ box.y2 = rect->y + rect->height - 1;
+
+ return pixman_region_contains_rectangle((pixman_region16_t *)region, &box);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_render.c b/src/lib/ecore_x/xcb/ecore_xcb_render.c
new file mode 100644
index 0000000000..f36b4d2489
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_render.c
@@ -0,0 +1,225 @@
+#include "ecore_xcb_private.h"
+#include <ctype.h> // for isupper/tolower
+#ifdef ECORE_XCB_RENDER
+# include <xcb/render.h>
+# include <xcb/xcb_renderutil.h>
+#endif
+
+/* local function prototypes */
+static Eina_Bool _ecore_xcb_render_parse_boolean(char *v);
+
+/* local variables */
+static Eina_Bool _render_avail = EINA_FALSE;
+static Eina_Bool _render_argb = EINA_FALSE;
+static Eina_Bool _render_anim = EINA_FALSE;
+
+void
+_ecore_xcb_render_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_RENDER
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_render_id);
+#endif
+}
+
+void
+_ecore_xcb_render_finalize(void)
+{
+#ifdef ECORE_XCB_RENDER
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_RENDER
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_render_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_render_query_version_cookie_t cookie;
+ xcb_render_query_version_reply_t *reply;
+
+ cookie =
+ xcb_render_query_version_unchecked(_ecore_xcb_conn,
+ XCB_RENDER_MAJOR_VERSION,
+ XCB_RENDER_MINOR_VERSION);
+ reply = xcb_render_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+// if ((reply->major_version >= XCB_RENDER_MAJOR_VERSION) &&
+ if (reply->minor_version >= XCB_RENDER_MINOR_VERSION)
+ {
+ char *v = NULL;
+
+ _render_avail = EINA_TRUE;
+ _ecore_xcb_xdefaults_init();
+ if ((reply->major_version > 0) || (reply->minor_version >= 5))
+ {
+ _render_argb = EINA_TRUE;
+ v = getenv("XCURSOR_CORE");
+ if (!v)
+ v = _ecore_xcb_xdefaults_string_get("Xcursor", "core");
+ if ((v) && (_ecore_xcb_render_parse_boolean(v)))
+ _render_argb = EINA_FALSE;
+ }
+ if ((_render_argb) &&
+ ((reply->major_version > 0) || (reply->minor_version >= 8)))
+ {
+ _render_anim = EINA_TRUE;
+ v = getenv("XCURSOR_ANIM");
+ if (!v)
+ v = _ecore_xcb_xdefaults_string_get("Xcursor", "anim");
+ if ((v) && (_ecore_xcb_render_parse_boolean(v)))
+ _render_anim = EINA_FALSE;
+ }
+ _ecore_xcb_xdefaults_shutdown();
+ }
+ }
+ free(reply);
+ }
+#endif
+}
+
+Eina_Bool
+_ecore_xcb_render_avail_get(void)
+{
+ return _render_avail;
+}
+
+Eina_Bool
+_ecore_xcb_render_argb_get(void)
+{
+ return _render_argb;
+}
+
+Eina_Bool
+_ecore_xcb_render_anim_get(void)
+{
+ return _render_anim;
+}
+
+Eina_Bool
+_ecore_xcb_render_visual_supports_alpha(Ecore_X_Visual visual)
+{
+ Eina_Bool ret = EINA_FALSE;
+#ifdef ECORE_XCB_RENDER
+ const xcb_render_query_pict_formats_reply_t *reply;
+ xcb_render_pictvisual_t *vis;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!visual) return EINA_FALSE;
+ if (!_render_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_RENDER
+ reply = xcb_render_util_query_formats(_ecore_xcb_conn);
+ if (!reply) return EINA_FALSE;
+
+ vis =
+ xcb_render_util_find_visual_format(reply,
+ ((xcb_visualtype_t *)visual)->visual_id);
+ if (vis)
+ {
+ xcb_render_pictforminfo_t temp;
+ xcb_render_pictforminfo_t *format;
+
+ temp.id = vis->format;
+ format =
+ xcb_render_util_find_format(reply, XCB_PICT_FORMAT_ID, &temp, 0);
+
+ if ((format->type == XCB_RENDER_PICT_TYPE_DIRECT) &&
+ (format->direct.alpha_mask))
+ ret = EINA_TRUE;
+ }
+
+#endif
+
+ return ret;
+}
+
+uint32_t
+_ecore_xcb_render_find_visual_id(int type,
+ Eina_Bool check_alpha)
+{
+#ifdef ECORE_XCB_RENDER
+ const xcb_render_query_pict_formats_reply_t *reply;
+ xcb_render_pictvisual_t *visual = NULL;
+ xcb_render_pictscreen_iterator_t screens;
+ xcb_render_pictdepth_iterator_t depths;
+ xcb_render_pictvisual_iterator_t visuals;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_render_avail) return 0;
+
+#ifdef ECORE_XCB_RENDER
+ reply = xcb_render_util_query_formats(_ecore_xcb_conn);
+ if (!reply) return 0;
+
+ for (screens = xcb_render_query_pict_formats_screens_iterator(reply);
+ screens.rem; xcb_render_pictscreen_next(&screens))
+ {
+ for (depths = xcb_render_pictscreen_depths_iterator(screens.data);
+ depths.rem; xcb_render_pictdepth_next(&depths))
+ {
+ for (visuals = xcb_render_pictdepth_visuals_iterator(depths.data);
+ visuals.rem; xcb_render_pictvisual_next(&visuals))
+ {
+ xcb_render_pictforminfo_t temp;
+ xcb_render_pictforminfo_t *format;
+
+ visual = visuals.data;
+ temp.id = visual->format;
+
+ format =
+ xcb_render_util_find_format(reply, XCB_PICT_FORMAT_ID,
+ &temp, 0);
+ if (!format) continue;
+ if (format->type == type)
+ {
+ if (check_alpha)
+ {
+ if (format->direct.alpha_mask)
+ return visual->visual;
+ }
+ else
+ return visual->visual;
+ }
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+/* local function prototypes */
+static Eina_Bool
+_ecore_xcb_render_parse_boolean(char *v)
+{
+ char c;
+
+ c = *v;
+ if (isupper((int)c))
+ c = tolower(c);
+ if ((c == 't') || (c == 'y') || (c == '1'))
+ return EINA_TRUE;
+ if ((c == 'f') || (c == 'n') || (c == '0'))
+ return EINA_FALSE;
+ if (c == 'o')
+ {
+ char d;
+
+ d = v[1];
+ if (isupper((int)d))
+ d = tolower(d);
+ if (d == 'n') return EINA_TRUE;
+ if (d == 'f') return EINA_FALSE;
+ }
+ return EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c b/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c
new file mode 100644
index 0000000000..6106450c88
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c
@@ -0,0 +1,370 @@
+#include "ecore_xcb_private.h"
+# ifdef ECORE_XCB_SCREENSAVER
+# include <xcb/screensaver.h>
+# endif
+
+/* local variables */
+static Eina_Bool _screensaver_avail = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_screensaver = -1;
+
+void
+_ecore_xcb_screensaver_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_screensaver_id);
+#endif
+}
+
+void
+_ecore_xcb_screensaver_finalize(void)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SCREENSAVER
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_screensaver_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_screensaver_query_version_cookie_t cookie;
+ xcb_screensaver_query_version_reply_t *reply;
+
+ cookie =
+ xcb_screensaver_query_version_unchecked(_ecore_xcb_conn,
+ XCB_SCREENSAVER_MAJOR_VERSION,
+ XCB_SCREENSAVER_MINOR_VERSION);
+ reply =
+ xcb_screensaver_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if ((reply->server_major_version >= XCB_SCREENSAVER_MAJOR_VERSION) &&
+ (reply->server_minor_version >= XCB_SCREENSAVER_MINOR_VERSION))
+ _screensaver_avail = EINA_TRUE;
+
+ free(reply);
+ }
+
+ if (_screensaver_avail)
+ _ecore_xcb_event_screensaver = ext_reply->first_event;
+ }
+#endif
+}
+
+EAPI int
+ecore_x_screensaver_idle_time_get(void)
+{
+ int ret = 0;
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_screensaver_query_info_cookie_t cookie;
+ xcb_screensaver_query_info_reply_t *reply;
+ Ecore_X_Window root;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return 0;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ cookie = xcb_screensaver_query_info_unchecked(_ecore_xcb_conn, root);
+ reply = xcb_screensaver_query_info_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ ret = (reply->ms_until_server / 1000);
+ free(reply);
+#endif
+
+ return ret;
+}
+
+EAPI void
+ecore_x_screensaver_set(int timeout,
+ int interval,
+ int prefer_blanking,
+ int allow_exposures)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_set_screen_saver(_ecore_xcb_conn,
+ timeout, interval, prefer_blanking, allow_exposures);
+#endif
+}
+
+EAPI void
+ecore_x_screensaver_timeout_set(int timeout)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+ uint16_t pint;
+ uint8_t pblank, pexpo;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ pint = reply->interval;
+ pblank = reply->prefer_blanking;
+ pexpo = reply->allow_exposures;
+ free(reply);
+ xcb_set_screen_saver(_ecore_xcb_conn, timeout, pint, pblank, pexpo);
+#endif
+}
+
+EAPI int
+ecore_x_screensaver_timeout_get(void)
+{
+ int timeout = 0;
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return 0;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ timeout = reply->timeout;
+ free(reply);
+#endif
+
+ return timeout;
+}
+
+EAPI void
+ecore_x_screensaver_blank_set(int blank)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+ uint16_t pint, pto;
+ uint8_t pexpo;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ pto = reply->timeout;
+ pint = reply->interval;
+ pexpo = reply->allow_exposures;
+ free(reply);
+ xcb_set_screen_saver(_ecore_xcb_conn, pto, pint, blank, pexpo);
+#endif
+}
+
+EAPI int
+ecore_x_screensaver_blank_get(void)
+{
+ int blank = 0;
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return 0;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ blank = reply->prefer_blanking;
+ free(reply);
+#endif
+
+ return blank;
+}
+
+EAPI void
+ecore_x_screensaver_expose_set(int expose)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+ uint16_t pint, pto;
+ uint8_t pblank;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ pto = reply->timeout;
+ pint = reply->interval;
+ pblank = reply->prefer_blanking;
+ free(reply);
+ xcb_set_screen_saver(_ecore_xcb_conn, pto, pint, pblank, expose);
+#endif
+}
+
+EAPI int
+ecore_x_screensaver_expose_get(void)
+{
+ int expose = 0;
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return 0;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ expose = reply->allow_exposures;
+ free(reply);
+#endif
+
+ return expose;
+}
+
+EAPI void
+ecore_x_screensaver_interval_set(int interval)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+ uint16_t pto;
+ uint8_t pblank, pexpose;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ pto = reply->timeout;
+ pblank = reply->prefer_blanking;
+ pexpose = reply->allow_exposures;
+ free(reply);
+ xcb_set_screen_saver(_ecore_xcb_conn, pto, interval, pblank, pexpose);
+#endif
+}
+
+EAPI int
+ecore_x_screensaver_interval_get(void)
+{
+ int interval = 0;
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_get_screen_saver_cookie_t cookie;
+ xcb_get_screen_saver_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return 0;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ interval = reply->interval;
+ free(reply);
+#endif
+
+ return interval;
+}
+
+EAPI void
+ecore_x_screensaver_event_listen_set(Eina_Bool on)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ Ecore_X_Window root;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_screensaver_avail) return;
+
+#ifdef ECORE_XCB_SCREENSAVER
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ if (on)
+ xcb_screensaver_select_input(_ecore_xcb_conn, root,
+ XCB_SCREENSAVER_EVENT_NOTIFY_MASK |
+ XCB_SCREENSAVER_EVENT_CYCLE_MASK);
+ else
+ xcb_screensaver_select_input(_ecore_xcb_conn, root, 0);
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_screensaver_event_available_get(void)
+{
+ return _screensaver_avail;
+}
+
+EAPI Eina_Bool
+ecore_x_screensaver_custom_blanking_enable(void)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ uint32_t mask_list[9];
+
+ xcb_screensaver_set_attributes_checked
+ (_ecore_xcb_conn,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ -9999, -9999, 1, 1, 0,
+ XCB_WINDOW_CLASS_INPUT_ONLY,
+ XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT,
+ 0, mask_list);
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_screensaver_custom_blanking_disable(void)
+{
+#ifdef ECORE_XCB_SCREENSAVER
+ xcb_screensaver_unset_attributes_checked
+ (_ecore_xcb_conn,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root);
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_selection.c b/src/lib/ecore_x/xcb/ecore_xcb_selection.c
new file mode 100644
index 0000000000..6d5c5aca4c
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_selection.c
@@ -0,0 +1,1026 @@
+#include "ecore_xcb_private.h"
+//#include "Ecore_X_Atoms.h"
+
+#define ECORE_XCB_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x))
+
+/* local function prototypes */
+static void *_ecore_xcb_selection_parser_text(const char *target EINA_UNUSED,
+ void *data,
+ int size,
+ int format EINA_UNUSED);
+static void *_ecore_xcb_selection_parser_files(const char *target,
+ void *data,
+ int size,
+ int format EINA_UNUSED);
+static void *_ecore_xcb_selection_parser_targets(const char *target EINA_UNUSED,
+ void *data,
+ int size,
+ int format EINA_UNUSED);
+
+//static int _ecore_xcb_selection_data_free(void *data);
+static int _ecore_xcb_selection_data_text_free(void *data);
+static int _ecore_xcb_selection_data_targets_free(void *data);
+static int _ecore_xcb_selection_data_files_free(void *data);
+static int _ecore_xcb_selection_data_default_free(void *data);
+static Eina_Bool _ecore_xcb_selection_set(Ecore_X_Window win,
+ const void *data,
+ int size,
+ Ecore_X_Atom selection);
+static void _ecore_xcb_selection_request(Ecore_X_Window win,
+ Ecore_X_Atom selection,
+ const char *target);
+static Ecore_X_Atom _ecore_xcb_selection_target_atom_get(const char *target);
+
+/* local variables */
+static Ecore_X_Selection_Intern _selections[4];
+static Ecore_X_Selection_Converter *_converters = NULL;
+static Ecore_X_Selection_Parser *_parsers = NULL;
+
+/* local functions */
+void
+_ecore_xcb_selection_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ memset(_selections, 0, sizeof(_selections));
+
+ /* init converters */
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT,
+ ecore_x_selection_converter_text);
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING,
+ ecore_x_selection_converter_text);
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT,
+ ecore_x_selection_converter_text);
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING,
+ ecore_x_selection_converter_text);
+
+ /* init parsers */
+ ecore_x_selection_parser_add("text/plain",
+ _ecore_xcb_selection_parser_text);
+ ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING,
+ _ecore_xcb_selection_parser_text);
+ ecore_x_selection_parser_add("text/uri-list",
+ _ecore_xcb_selection_parser_files);
+ ecore_x_selection_parser_add("_NETSCAPE_URL",
+ _ecore_xcb_selection_parser_files);
+ ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS,
+ _ecore_xcb_selection_parser_targets);
+}
+
+void
+_ecore_xcb_selection_shutdown(void)
+{
+ Ecore_X_Selection_Converter *cnv;
+ Ecore_X_Selection_Parser *prs;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ /* free selection converters */
+ cnv = _converters;
+ while (cnv)
+ {
+ Ecore_X_Selection_Converter *tmp;
+
+ tmp = cnv->next;
+ free(cnv);
+ cnv = tmp;
+ }
+ _converters = NULL;
+
+ /* free parsers */
+ prs = _parsers;
+ while (prs)
+ {
+ Ecore_X_Selection_Parser *tmp;
+
+ tmp = prs;
+ prs = prs->next;
+ free(tmp->target);
+ free(tmp);
+ }
+ _parsers = NULL;
+}
+
+/* public functions */
+EAPI void
+ecore_x_selection_converter_atom_add(Ecore_X_Atom target,
+ Eina_Bool (*func)(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *type,
+ int *size_type))
+{
+ Ecore_X_Selection_Converter *cnv;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ cnv = _converters;
+ if (_converters)
+ {
+ while (1)
+ {
+ if (cnv->target == target)
+ {
+ cnv->convert = func;
+ return;
+ }
+ if (cnv->next)
+ cnv = cnv->next;
+ else
+ break;
+ }
+ cnv->next = calloc(1, sizeof(Ecore_X_Selection_Converter));
+ if (!cnv->next) return;
+ cnv = cnv->next;
+ }
+ else
+ {
+ _converters = calloc(1, sizeof(Ecore_X_Selection_Converter));
+ if (!_converters) return;
+ cnv = _converters;
+ }
+ cnv->target = target;
+ cnv->convert = func;
+}
+
+EAPI void
+ecore_x_selection_converter_add(char *target,
+ Eina_Bool (*func)(char *target,
+ void *data,
+ int size,
+ void **date_ret,
+ int *size_ret,
+ Ecore_X_Atom *atom_ret,
+ int *ret))
+{
+ Ecore_X_Atom atarget;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((!func) || (!target)) return;
+ atarget = _ecore_xcb_selection_target_atom_get(target);
+ ecore_x_selection_converter_atom_add(atarget, func);
+}
+
+EAPI void
+ecore_x_selection_converter_del(char *target)
+{
+ Ecore_X_Atom atarget;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!target) return;
+ atarget = _ecore_xcb_selection_target_atom_get(target);
+ ecore_x_selection_converter_atom_del(atarget);
+}
+
+EAPI void
+ecore_x_selection_converter_atom_del(Ecore_X_Atom target)
+{
+ Ecore_X_Selection_Converter *conv, *pconv = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ conv = _converters;
+ while (conv)
+ {
+ if (conv->target == target)
+ {
+ if (pconv)
+ pconv->next = conv->next;
+ else
+ _converters = conv->next;
+ free(conv);
+ return;
+ }
+ pconv = conv;
+ conv = conv->next;
+ }
+}
+
+EAPI void
+ecore_x_selection_parser_add(const char *target,
+ void *(*func)(const char *target, void *data, int size, int format))
+{
+ Ecore_X_Selection_Parser *prs;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!target) return;
+ prs = _parsers;
+ if (prs)
+ {
+ while (prs->next)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ prs->parse = func;
+ return;
+ }
+ prs = prs->next;
+ }
+ prs->next = calloc(1, sizeof(Ecore_X_Selection_Parser));
+ prs = prs->next;
+ }
+ else
+ {
+ _parsers = calloc(1, sizeof(Ecore_X_Selection_Parser));
+ prs = _parsers;
+ }
+ prs->target = strdup(target);
+ prs->parse = func;
+}
+
+EAPI void
+ecore_x_selection_parser_del(const char *target)
+{
+ Ecore_X_Selection_Parser *prs, *pprs = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!target) return;
+
+ prs = _parsers;
+ while (prs)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ if (pprs)
+ pprs->next = prs->next;
+ else
+ _parsers = prs->next;
+ free(prs->target);
+ free(prs);
+ return;
+ }
+ pprs = prs;
+ prs = prs->next;
+ }
+}
+
+/**
+ * Claim ownership of the PRIMARY selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_primary_set(Ecore_X_Window win,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(win, data, size,
+ ECORE_X_ATOM_SELECTION_PRIMARY);
+}
+
+/**
+ * Release ownership of the primary selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_primary_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(XCB_NONE, NULL, 0,
+ ECORE_X_ATOM_SELECTION_PRIMARY);
+}
+
+EAPI void
+ecore_x_selection_primary_request(Ecore_X_Window win,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_PRIMARY, target);
+}
+
+/**
+ * Claim ownership of the SECONDARY selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_secondary_set(Ecore_X_Window win,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(win, data, size,
+ ECORE_X_ATOM_SELECTION_SECONDARY);
+}
+
+/**
+ * Release ownership of the secondary selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_secondary_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(XCB_NONE, NULL, 0,
+ ECORE_X_ATOM_SELECTION_SECONDARY);
+}
+
+EAPI void
+ecore_x_selection_secondary_request(Ecore_X_Window win,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_SECONDARY, target);
+}
+
+/**
+ * Claim ownership of the XDND selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_xdnd_set(Ecore_X_Window win,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(win, data, size,
+ ECORE_X_ATOM_SELECTION_XDND);
+}
+
+/**
+ * Release ownership of the XDND selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_xdnd_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(XCB_NONE, NULL, 0,
+ ECORE_X_ATOM_SELECTION_XDND);
+}
+
+EAPI void
+ecore_x_selection_xdnd_request(Ecore_X_Window win,
+ const char *target)
+{
+ Ecore_X_Atom atom;
+ Ecore_X_DND_Target *_target;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ _target = _ecore_xcb_dnd_target_get();
+ atom = _ecore_xcb_selection_target_atom_get(target);
+
+ xcb_convert_selection(_ecore_xcb_conn, win, ECORE_X_ATOM_SELECTION_XDND,
+ atom, ECORE_X_ATOM_SELECTION_PROP_XDND, _target->time);
+}
+
+/**
+ * Claim ownership of the CLIPBOARD selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ *
+ * Get the converted data from a previous CLIPBOARD selection
+ * request. The buffer must be freed when done with.
+ */
+EAPI Eina_Bool
+ecore_x_selection_clipboard_set(Ecore_X_Window win,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(win, data, size,
+ ECORE_X_ATOM_SELECTION_CLIPBOARD);
+}
+
+/**
+ * Release ownership of the clipboard selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_clipboard_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_selection_set(XCB_NONE, NULL, 0,
+ ECORE_X_ATOM_SELECTION_CLIPBOARD);
+}
+
+EAPI void
+ecore_x_selection_clipboard_request(Ecore_X_Window win,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_CLIPBOARD, target);
+}
+
+EAPI Eina_Bool
+ecore_x_selection_convert(Ecore_X_Atom selection,
+ Ecore_X_Atom target,
+ void **data_ret,
+ int *size,
+ Ecore_X_Atom *targtype,
+ int *typesize)
+{
+ Ecore_X_Selection_Intern *sel;
+ Ecore_X_Selection_Converter *cnv;
+ void *data;
+ char *tgt_str;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ sel = _ecore_xcb_selection_get(selection);
+ tgt_str = _ecore_xcb_selection_target_get(target);
+
+ for (cnv = _converters; cnv; cnv = cnv->next)
+ {
+ if (cnv->target == target)
+ {
+ int r = 0;
+
+ r = cnv->convert(tgt_str, sel->data, sel->length, &data, size,
+ targtype, typesize);
+ free(tgt_str);
+ if (r)
+ {
+ if (data_ret) *data_ret = data;
+ return r;
+ }
+ else
+ return EINA_FALSE;
+ }
+ }
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_selection_notify_send(Ecore_X_Window requestor,
+ Ecore_X_Atom selection,
+ Ecore_X_Atom target,
+ Ecore_X_Atom property,
+ Ecore_X_Time tim)
+{
+ xcb_selection_notify_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ memset(&ev, 0, sizeof(xcb_selection_notify_event_t));
+
+ ev.response_type = XCB_SELECTION_NOTIFY;
+ ev.requestor = requestor;
+ ev.selection = selection;
+ ev.target = target;
+ ev.property = property;
+ ev.time = tim;
+
+ xcb_send_event(_ecore_xcb_conn, 0, requestor,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
+// ecore_x_flush();
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_selection_owner_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Time tim)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_set_selection_owner(_ecore_xcb_conn, win, atom, tim);
+}
+
+EAPI Ecore_X_Window
+ecore_x_selection_owner_get(Ecore_X_Atom atom)
+{
+ xcb_get_selection_owner_cookie_t cookie;
+ xcb_get_selection_owner_reply_t *reply;
+ Ecore_X_Window ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_selection_owner(_ecore_xcb_conn, atom);
+ reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ ret = reply->owner;
+ free(reply);
+ return ret;
+}
+
+void *
+_ecore_xcb_selection_parse(const char *target,
+ void *data,
+ int size,
+ int format)
+{
+ Ecore_X_Selection_Parser *prs;
+ Ecore_X_Selection_Data *sel;
+
+ for (prs = _parsers; prs; prs = prs->next)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ sel = prs->parse(target, data, size, format);
+ if (sel) return sel;
+ }
+ }
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data));
+ if (!sel) return NULL;
+ sel->free = _ecore_xcb_selection_data_default_free;
+ sel->length = size;
+ sel->format = format;
+ sel->data = data;
+
+ return sel;
+}
+
+Ecore_X_Selection_Intern *
+_ecore_xcb_selection_get(Ecore_X_Atom selection)
+{
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ return &_selections[0];
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ return &_selections[1];
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ return &_selections[2];
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ return &_selections[3];
+ else
+ return NULL;
+}
+
+/* local functions */
+static Eina_Bool
+_ecore_xcb_selection_set(Ecore_X_Window win,
+ const void *data,
+ int size,
+ Ecore_X_Atom selection)
+{
+ xcb_get_selection_owner_cookie_t cookie;
+ xcb_get_selection_owner_reply_t *reply;
+ int in = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_set_selection_owner(_ecore_xcb_conn, win, selection, XCB_CURRENT_TIME);
+
+ cookie = xcb_get_selection_owner(_ecore_xcb_conn, selection);
+ reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ if (reply->owner != win)
+ {
+ free(reply);
+ return EINA_FALSE;
+ }
+ free(reply);
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ in = 0;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ in = 1;
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ in = 2;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ in = 3;
+ else
+ return EINA_FALSE;
+
+ if (data)
+ {
+ unsigned char *buff = NULL;
+
+ _selections[in].win = win;
+ _selections[in].selection = selection;
+ _selections[in].length = size;
+ _selections[in].time = _ecore_xcb_events_last_time_get();
+
+ buff = malloc(size);
+ if (!buff) return EINA_FALSE;
+ memcpy(buff, data, size);
+ _selections[in].data = buff;
+ }
+ else if (_selections[in].data)
+ {
+ free(_selections[in].data);
+ memset(&_selections[in], 0, sizeof(Ecore_X_Selection_Data));
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_xcb_selection_request(Ecore_X_Window win,
+ Ecore_X_Atom selection,
+ const char *target)
+{
+ Ecore_X_Atom atarget, prop;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
+ else
+ return;
+
+ atarget = _ecore_xcb_selection_target_atom_get(target);
+
+ xcb_convert_selection(_ecore_xcb_conn, win, selection, atarget, prop,
+ XCB_CURRENT_TIME);
+}
+
+EAPI Eina_Bool
+ecore_x_selection_converter_text(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *type EINA_UNUSED,
+ int *size_type EINA_UNUSED)
+{
+ Ecore_Xcb_Encoding_Style style;
+ Ecore_Xcb_Textproperty ret;
+ char *str;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!data) || (!size)) return EINA_FALSE;
+
+ if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
+ style = XcbTextStyle;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
+ style = XcbCompoundTextStyle;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
+ style = XcbStringStyle;
+#ifdef HAVE_ICONV
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
+ style = XcbUTF8StringStyle;
+#endif
+ else
+ return EINA_FALSE;
+
+ str = alloca(size + 1);
+ memcpy(str, data, size);
+ str[size] = '\0';
+
+#ifdef HAVE_ICONV
+ if (_ecore_xcb_utf8_textlist_to_textproperty(&str, 1, style, &ret))
+ {
+ int size = 0;
+
+ size = (strlen((char *)ret.value) + 1);
+ *data_ret = malloc(size);
+ if (!*data_ret) return EINA_FALSE;
+ memcpy(*data_ret, ret.value, size);
+ *size_ret = size;
+ if (ret.value) free(ret.value);
+ return EINA_TRUE;
+ }
+#else
+ if (_ecore_xcb_mb_textlist_to_textproperty(&str, 1, style, &ret))
+ {
+ int size = 0;
+
+ size = (strlen((char *)ret.value) + 1);
+ *data_ret = malloc(size);
+ if (!*data_ret) return EINA_FALSE;
+ memcpy(*data_ret, ret.value, size);
+ *size_ret = size;
+ if (ret.value) free(ret.value);
+ return EINA_TRUE;
+ }
+#endif
+ else
+ return EINA_TRUE;
+}
+
+static void *
+_ecore_xcb_selection_parser_text(const char *target EINA_UNUSED,
+ void *data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Text *sel;
+ unsigned char *_data;
+ void *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(_data = data)) return NULL;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text));
+ if (!sel) return NULL;
+
+ if (_data && _data[size - 1])
+ {
+ size++;
+ t = realloc(_data, size);
+ if (!t)
+ {
+ free(sel);
+ return NULL;
+ }
+ _data = t;
+ _data[size - 1] = 0;
+ }
+ sel->text = (char *)_data;
+ ECORE_XCB_SELECTION_DATA(sel)->length = size;
+ ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT;
+ ECORE_XCB_SELECTION_DATA(sel)->data = _data;
+ ECORE_XCB_SELECTION_DATA(sel)->free = _ecore_xcb_selection_data_text_free;
+ return sel;
+}
+
+static void *
+_ecore_xcb_selection_parser_files(const char *target,
+ void *data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Files *sel;
+ char *_data, *tmp, *t, **t2;
+ int i = 0, is = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if ((strcmp(target, "text/uri-list")) &&
+ (strcmp(target, "_NETSCAPE_URL"))) return NULL;
+
+ if (!(_data = data)) return NULL;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files));
+ if (!sel) return NULL;
+
+ ECORE_XCB_SELECTION_DATA(sel)->free = _ecore_xcb_selection_data_files_free;
+
+ if (_data && _data[size - 1])
+ {
+ size++;
+ t = realloc(_data, size);
+ if (!t)
+ {
+ free(sel);
+ return NULL;
+ }
+ _data = t;
+ _data[size - 1] = 0;
+ }
+
+ tmp = malloc(size);
+ if (!tmp)
+ {
+ free(sel);
+ return NULL;
+ }
+
+ while ((is < size) && (_data[is]))
+ {
+ if ((i == 0) && (_data[is] == '#'))
+ {
+ for (; ((_data[is]) && (_data[is] != '\n')); is++) ;
+ }
+ else
+ {
+ if ((_data[is] != '\r') && (_data[is] != '\n'))
+ tmp[i++] = _data[is++];
+ else
+ {
+ while ((_data[is] == '\r') || (_data[is] == '\n'))
+ is++;
+ tmp[i] = 0;
+ sel->num_files++;
+ t2 = realloc(sel->files, sel->num_files * sizeof(char *));
+ if (t2)
+ {
+ sel->files = t2;
+ sel->files[sel->num_files - 1] = strdup(tmp);
+ }
+ tmp[0] = 0;
+ i = 0;
+ }
+ }
+ }
+ if (i > 0)
+ {
+ tmp[i] = 0;
+ sel->num_files++;
+ t2 = realloc(sel->files, sel->num_files * sizeof(char *));
+ if (t2)
+ {
+ sel->files = t2;
+ sel->files[sel->num_files - 1] = strdup(tmp);
+ }
+ }
+ if (tmp) free(tmp);
+ if (_data) free(_data);
+
+ ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES;
+ ECORE_XCB_SELECTION_DATA(sel)->length = sel->num_files;
+
+ return ECORE_XCB_SELECTION_DATA(sel);
+}
+
+static void *
+_ecore_xcb_selection_parser_targets(const char *target EINA_UNUSED,
+ void *data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Targets *sel;
+ unsigned long *targets;
+ int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!(targets = (unsigned long *)data)) return NULL;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets));
+ if (!sel) return NULL;
+
+ sel->num_targets = (size - 2);
+ sel->targets = malloc((size - 2) * sizeof(char *));
+ if (!sel->targets)
+ {
+ free(sel);
+ return NULL;
+ }
+
+ for (i = 2; i < size; i++)
+ {
+ xcb_get_atom_name_cookie_t cookie;
+ xcb_get_atom_name_reply_t *reply;
+ char *name = NULL;
+ int len = 0;
+
+ cookie = xcb_get_atom_name_unchecked(_ecore_xcb_conn, targets[i]);
+ reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ len = xcb_get_atom_name_name_length(reply);
+ name = (char *)malloc(sizeof(char) * (len + 1));
+ if (name)
+ {
+ memcpy(name, xcb_get_atom_name_name(reply), len);
+ name[len] = '\0';
+ sel->targets[i - 2] = name;
+ }
+ free(reply);
+ }
+ }
+
+ ECORE_XCB_SELECTION_DATA(sel)->free =
+ _ecore_xcb_selection_data_targets_free;
+ ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS;
+ ECORE_XCB_SELECTION_DATA(sel)->length = size;
+ ECORE_XCB_SELECTION_DATA(sel)->data = data;
+
+ return sel;
+}
+
+/*
+ static int
+ _ecore_xcb_selection_data_free(void *data)
+ {
+ Ecore_X_Selection_Data *sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sel = data)) return 0;
+ if (sel->data) free(sel->data);
+ free(sel);
+ return 1;
+ }
+ */
+
+static int
+_ecore_xcb_selection_data_text_free(void *data)
+{
+ Ecore_X_Selection_Data_Text *sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sel = data)) return 0;
+ if (sel->text) free(sel->text);
+ free(sel);
+ return 1;
+}
+
+static int
+_ecore_xcb_selection_data_targets_free(void *data)
+{
+ Ecore_X_Selection_Data_Targets *sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sel = data)) return 0;
+ if (sel->targets) free(sel->targets);
+ free(ECORE_XCB_SELECTION_DATA(sel)->data);
+ free(sel);
+ return 1;
+}
+
+static int
+_ecore_xcb_selection_data_files_free(void *data)
+{
+ Ecore_X_Selection_Data_Files *sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!(sel = data)) return 0;
+ if (sel->files)
+ {
+ int i = 0;
+
+ for (i = 0; i < sel->num_files; i++)
+ if (sel->files[i]) free(sel->files[i]);
+ if (sel->files) free(sel->files);
+ }
+ free(sel);
+ return 0;
+}
+
+static int
+_ecore_xcb_selection_data_default_free(void *data)
+{
+ Ecore_X_Selection_Data *sel;
+
+ if (!(sel = data)) return 1;
+ free(sel->data);
+ free(sel);
+ return 1;
+}
+
+static Ecore_X_Atom
+_ecore_xcb_selection_target_atom_get(const char *target)
+{
+ Ecore_X_Atom x_target;
+
+ if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
+ x_target = ECORE_X_ATOM_TEXT;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
+ x_target = ECORE_X_ATOM_COMPOUND_TEXT;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
+ x_target = ECORE_X_ATOM_STRING;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
+ x_target = ECORE_X_ATOM_UTF8_STRING;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME))
+ x_target = ECORE_X_ATOM_FILE_NAME;
+ else
+ x_target = ecore_x_atom_get(target);
+
+ return x_target;
+}
+
+char *
+_ecore_xcb_selection_target_get(Ecore_X_Atom target)
+{
+ if (target == ECORE_X_ATOM_FILE_NAME)
+ return strdup(ECORE_X_SELECTION_TARGET_FILENAME);
+ else if (target == ECORE_X_ATOM_STRING)
+ return strdup(ECORE_X_SELECTION_TARGET_STRING);
+ else if (target == ECORE_X_ATOM_UTF8_STRING)
+ return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING);
+ else if (target == ECORE_X_ATOM_TEXT)
+ return strdup(ECORE_X_SELECTION_TARGET_TEXT);
+ else
+ return ecore_x_atom_name_get(target);
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_shape.c b/src/lib/ecore_x/xcb/ecore_xcb_shape.c
new file mode 100644
index 0000000000..913f1992b9
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_shape.c
@@ -0,0 +1,50 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_SHAPE
+# include <xcb/shape.h>
+#endif
+
+/* external variables */
+int _ecore_xcb_event_shape = -1;
+
+void
+_ecore_xcb_shape_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shape_id);
+#endif
+}
+
+void
+_ecore_xcb_shape_finalize(void)
+{
+#ifdef ECORE_XCB_SHAPE
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SHAPE
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_shape_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_shape_query_version_cookie_t cookie;
+ xcb_shape_query_version_reply_t *reply;
+ Eina_Bool _shape_avail;
+
+ _shape_avail = EINA_FALSE;
+ cookie = xcb_shape_query_version_unchecked(_ecore_xcb_conn);
+ reply = xcb_shape_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ _shape_avail = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_shape_avail)
+ _ecore_xcb_event_shape = ext_reply->first_event;
+ }
+#endif
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_sync.c b/src/lib/ecore_x/xcb/ecore_xcb_sync.c
new file mode 100644
index 0000000000..75f4e4f2be
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_sync.c
@@ -0,0 +1,338 @@
+#include "ecore_xcb_private.h"
+# ifdef ECORE_XCB_SYNC
+# include <xcb/sync.h>
+# endif
+
+/* local variables */
+static Eina_Bool _sync_avail = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_sync = -1;
+
+void
+_ecore_xcb_sync_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SYNC
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_sync_id);
+#endif
+}
+
+void
+_ecore_xcb_sync_finalize(void)
+{
+#ifdef ECORE_XCB_SYNC
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_SYNC
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_sync_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_sync_initialize_cookie_t cookie;
+ xcb_sync_initialize_reply_t *reply;
+
+ cookie =
+ xcb_sync_initialize_unchecked(_ecore_xcb_conn,
+ XCB_SYNC_MAJOR_VERSION,
+ XCB_SYNC_MINOR_VERSION);
+ reply = xcb_sync_initialize_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if (reply->major_version >= 3) _sync_avail = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_sync_avail)
+ _ecore_xcb_event_sync = ext_reply->first_event;
+ }
+#endif
+}
+
+void
+_ecore_xcb_sync_magic_send(int val,
+ Ecore_X_Window win)
+{
+ xcb_client_message_event_t ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = win;
+ ev.type = 27777;
+ ev.data.data32[0] = 0x7162534;
+ ev.data.data32[1] = (0x10000000 + val);
+ ev.data.data32[2] = win;
+
+ xcb_send_event(_ecore_xcb_conn, 0, win, XCB_EVENT_MASK_NO_EVENT,
+ (const char *)&ev);
+// ecore_x_flush();
+}
+
+/* public functions */
+EAPI Ecore_X_Sync_Alarm
+ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter)
+{
+#ifdef ECORE_XCB_SYNC
+ uint32_t list[6], mask;
+ xcb_sync_int64_t init;
+ Ecore_X_Sync_Alarm alarm;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return 0;
+
+#ifdef ECORE_XCB_SYNC
+ init.lo = 0;
+ init.hi = 0;
+ xcb_sync_set_counter(_ecore_xcb_conn, counter, init);
+
+ mask = (XCB_SYNC_CA_COUNTER | XCB_SYNC_CA_VALUE_TYPE |
+ XCB_SYNC_CA_VALUE | XCB_SYNC_CA_TEST_TYPE |
+ XCB_SYNC_CA_DELTA | XCB_SYNC_CA_EVENTS);
+ list[0] = counter;
+ list[1] = XCB_SYNC_VALUETYPE_ABSOLUTE;
+ list[2] = 1;
+ list[3] = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON;
+ list[4] = 1;
+ list[5] = 1;
+ alarm = xcb_generate_id(_ecore_xcb_conn);
+
+ xcb_sync_create_alarm(_ecore_xcb_conn, alarm, mask, list);
+ ecore_x_sync(); // needed
+
+ return alarm;
+#endif
+ return 0;
+}
+
+EAPI Eina_Bool
+ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!alarm)) return EINA_FALSE;
+
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_destroy_alarm(_ecore_xcb_conn, alarm);
+// ecore_x_flush();
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter,
+ unsigned int *val)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_query_counter_cookie_t cookie;
+ xcb_sync_query_counter_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return EINA_FALSE;
+
+#ifdef ECORE_XCB_SYNC
+ cookie = xcb_sync_query_counter_unchecked(_ecore_xcb_conn, counter);
+ reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ if (val) *val = (unsigned int)reply->counter_value.lo;
+ free(reply);
+ return EINA_TRUE;
+ }
+#endif
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter,
+ int by)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_int64_t v;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return;
+
+#ifdef ECORE_XCB_SYNC
+ v.hi = (by < 0) ? ~0 : 0;
+ v.lo = by;
+
+ xcb_sync_change_counter(_ecore_xcb_conn, counter, v);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter,
+ int val)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_query_counter_cookie_t cookie;
+ xcb_sync_query_counter_reply_t *reply;
+ xcb_sync_int64_t v1, v2;
+ xcb_sync_waitcondition_t cond;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return;
+
+#ifdef ECORE_XCB_SYNC
+ cookie = xcb_sync_query_counter_unchecked(_ecore_xcb_conn, counter);
+ reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ v1 = reply->counter_value;
+ free(reply);
+
+ v1.hi = (val < 0) ? ~0 : 0;
+ v1.lo = val;
+ v2.hi = ((val + 1) < 0) ? ~0 : 0;
+ v2.lo = (val + 1);
+
+ cond.trigger.counter = counter;
+ cond.trigger.wait_type = XCB_SYNC_VALUETYPE_ABSOLUTE;
+ cond.trigger.wait_value = v1;
+ cond.trigger.test_type = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON;
+ cond.event_threshold = v2;
+
+ xcb_sync_await(_ecore_xcb_conn, 1, &cond);
+// ecore_x_flush();
+#endif
+}
+
+EAPI Ecore_X_Sync_Counter
+ecore_x_sync_counter_new(int val)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_counter_t counter;
+ xcb_sync_int64_t v;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_sync_avail) return 0;
+
+#ifdef ECORE_XCB_SYNC
+ v.hi = (val < 0) ? ~0 : 0;
+ v.lo = val;
+
+ counter = xcb_generate_id(_ecore_xcb_conn);
+ xcb_sync_create_counter(_ecore_xcb_conn, counter, v);
+// ecore_x_flush();
+
+ return counter;
+#endif
+
+ return 0;
+}
+
+EAPI void
+ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return;
+
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_destroy_counter(_ecore_xcb_conn, counter);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter,
+ int val)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_int64_t v;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return;
+
+#ifdef ECORE_XCB_SYNC
+ v.hi = (val < 0) ? ~0 : 0;
+ v.lo = val;
+
+ xcb_sync_set_counter(_ecore_xcb_conn, counter, v);
+// ecore_x_flush();
+#endif
+}
+
+EAPI void
+ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter,
+ int val_hi,
+ unsigned int val_lo)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_int64_t v;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return;
+
+#ifdef ECORE_XCB_SYNC
+ v.hi = val_hi;
+ v.lo = val_lo;
+
+ xcb_sync_set_counter(_ecore_xcb_conn, counter, v);
+// ecore_x_flush();
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter,
+ int *val_hi,
+ unsigned int *val_lo)
+{
+#ifdef ECORE_XCB_SYNC
+ xcb_sync_query_counter_cookie_t cookie;
+ xcb_sync_query_counter_reply_t *reply;
+ xcb_sync_int64_t value;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if ((!_sync_avail) || (!counter)) return EINA_FALSE;
+
+#ifdef ECORE_XCB_SYNC
+ cookie =
+ xcb_sync_query_counter_unchecked(_ecore_xcb_conn,
+ (xcb_sync_counter_t)counter);
+ reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+ value = reply->counter_value;
+ free(reply);
+ if (val_hi) *val_hi = (int)value.hi;
+ if (val_lo) *val_lo = (unsigned int)value.lo;
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_textlist.c b/src/lib/ecore_x/xcb/ecore_xcb_textlist.c
new file mode 100644
index 0000000000..2a5c854494
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_textlist.c
@@ -0,0 +1,509 @@
+#include "ecore_xcb_private.h"
+//#include "Ecore_X_Atoms.h"
+#include <langinfo.h>
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#endif
+#ifndef CODESET
+# define CODESET "INVALID"
+#endif
+
+static int _ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide,
+ void *list,
+ int count);
+static int _ecore_xcb_textlist_get_wc_len(wchar_t *wstr);
+static void *_ecore_xcb_textlist_alloc_list(Eina_Bool is_wide,
+ int count,
+ int nitems);
+static void _ecore_xcb_textlist_copy_list(Eina_Bool is_wide,
+ void *text,
+ char **list,
+ int count);
+static wchar_t *_ecore_xcb_textlist_copy_wchar(wchar_t *str1,
+ wchar_t *str2);
+static int _ecore_xcb_textlist_len_wchar(wchar_t *str);
+
+#ifdef HAVE_ICONV
+Eina_Bool
+_ecore_xcb_utf8_textlist_to_textproperty(char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_textlist_to_textproperty("utf8string", list, count,
+ style, ret);
+}
+
+#endif
+
+Eina_Bool
+_ecore_xcb_mb_textlist_to_textproperty(char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_textlist_to_textproperty("multiByte", list, count,
+ style, ret);
+}
+
+/* NB: This Function May Not Be Correct !!!
+ * (as I do not know text conversion, locales, etc, etc very well)
+ *
+ * Portions were ripped from libX11 XTextListToTextProperty
+ */
+Eina_Bool
+_ecore_xcb_textlist_to_textproperty(const char *type,
+ char **list,
+ int count,
+ Ecore_Xcb_Encoding_Style style,
+ Ecore_Xcb_Textproperty *ret)
+{
+ Eina_Bool is_wide = EINA_FALSE;
+ Ecore_X_Atom encoding;
+ int len = 0, nitems = 0, i = 0;
+ size_t from_left = 0, to_left = 0;
+ int unconv_num = 0, val = 0;
+ char *buff, *to, *value, *from;
+ const char *to_type, *from_type;
+ char **mb = NULL;
+ wchar_t **wc = NULL;
+#ifdef HAVE_ICONV
+ iconv_t conv;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!strcmp("wideChar", type)) is_wide = EINA_TRUE;
+ len = _ecore_xcb_textlist_get_buffer_size(is_wide, list, count);
+ if (!(buff = (char *)malloc(len * sizeof(char)))) return EINA_FALSE;
+ from_type = nl_langinfo(CODESET);
+ switch (style)
+ {
+ case XcbStringStyle:
+ case XcbStdICCTextStyle:
+ encoding = ECORE_X_ATOM_STRING;
+ to_type = nl_langinfo(CODESET);
+// to_type = "string";
+ break;
+
+ case XcbUTF8StringStyle:
+ encoding = ECORE_X_ATOM_UTF8_STRING;
+ to_type = "UTF-8";
+ break;
+
+ case XcbCompoundTextStyle:
+ encoding = ECORE_X_ATOM_COMPOUND_TEXT;
+ to_type = nl_langinfo(CODESET);
+// to_type = "compoundText";
+ break;
+
+ case XcbTextStyle:
+ encoding = ECORE_X_ATOM_TEXT;
+ to_type = nl_langinfo(CODESET);
+// to_type = "multiByte";
+ if (!is_wide)
+ {
+ nitems = 0;
+ mb = (char **)list;
+ to = buff;
+ for (i = 0; ((i < count) && (len > 0)); i++)
+ {
+ if (*mb) strcpy(to, *mb);
+ else *to = '\0';
+ from_left = (*mb ? strlen(*mb) : 0) + 1;
+ nitems += from_left;
+ to += from_left;
+ mb++;
+ }
+ unconv_num = 0;
+ goto done;
+ }
+ break;
+
+ default:
+ free(buff);
+ return EINA_FALSE;
+ break;
+ }
+
+ if (count < 1)
+ {
+ nitems = 0;
+ goto done;
+ }
+
+retry:
+#ifdef HAVE_ICONV
+ conv = iconv_open(to_type, from_type);
+#endif
+
+ if (is_wide)
+ wc = (wchar_t **)list;
+ else
+ mb = (char **)list;
+
+ to = buff;
+ to_left = len;
+ unconv_num = 0;
+ for (i = 1; to_left > 0; i++)
+ {
+ if (is_wide)
+ {
+ from = (char *)*wc;
+ from_left = _ecore_xcb_textlist_get_wc_len(*wc);
+ wc++;
+ }
+ else
+ {
+ from = *mb;
+ from_left = (*mb ? strlen(*mb) : 0);
+ mb++;
+ }
+
+#ifdef HAVE_ICONV
+ val = iconv(conv, &from, &from_left, &to, &to_left);
+#endif
+ if (val < 0) continue;
+ if ((val > 0) && (style == XcbStdICCTextStyle) &&
+ (encoding == ECORE_X_ATOM_STRING))
+ {
+#ifdef HAVE_ICONV
+ iconv_close(conv);
+#endif
+ encoding = ECORE_X_ATOM_COMPOUND_TEXT;
+ goto retry;
+ }
+
+ unconv_num += val;
+ *to++ = '\0';
+ to_left--;
+ if (i >= count) break;
+ }
+
+#ifdef HAVE_ICONV
+ iconv_close(conv);
+#endif
+ nitems = (to - buff);
+
+done:
+ if (nitems <= 0) nitems = 1;
+ if (!(value = (char *)malloc(nitems * sizeof(char))))
+ {
+ free(buff);
+ return EINA_FALSE;
+ }
+ if (nitems == 1)
+ *value = 0;
+ else
+ memcpy(value, buff, nitems);
+ nitems--;
+ free(buff);
+
+ ret->value = value;
+ ret->encoding = encoding;
+ ret->format = 8;
+ ret->nitems = nitems;
+
+ return EINA_TRUE;
+}
+
+#ifdef HAVE_ICONV
+Eina_Bool
+_ecore_xcb_utf8_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ char ***list_ret,
+ int *count_ret)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_textproperty_to_textlist(text_prop, "utf8String",
+ list_ret, count_ret);
+}
+
+#endif
+
+Eina_Bool
+_ecore_xcb_mb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ char ***list_ret,
+ int *count_ret)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return _ecore_xcb_textproperty_to_textlist(text_prop, "multiByte",
+ list_ret, count_ret);
+}
+
+Eina_Bool
+_ecore_xcb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
+ const char *type,
+ char ***list_ret,
+ int *count_ret)
+{
+ Eina_Bool is_wide = EINA_FALSE;
+ Eina_Bool do_strcpy = EINA_FALSE;
+ const char *from_type;
+ char *buff, *to, *from;
+ char *lptr, *sptr;
+ int nitems = 0, len = 0, num = 0, ret = 0;
+ size_t from_left = 0, to_left = 0;
+#ifdef HAVE_ICONV
+ iconv_t conv = 0;
+#endif
+
+ *list_ret = NULL;
+ *count_ret = 0;
+ if (!strcmp("wideChar", type)) is_wide = EINA_TRUE;
+
+ nitems = text_prop->nitems;
+ if (nitems <= 0) return EINA_TRUE;
+
+ if (text_prop->format != 8) return EINA_FALSE;
+
+ from_type = nl_langinfo(CODESET);
+ if (text_prop->encoding == ECORE_X_ATOM_UTF8_STRING)
+ from_type = "UTF-8";
+
+ if (is_wide)
+ len = (text_prop->nitems + 1) * sizeof(wchar_t);
+ else
+ {
+ if (!strcmp(type, "utf8String"))
+ len = text_prop->nitems * 6 + 1;
+ else
+ len = text_prop->nitems * MB_CUR_MAX + 1;
+ }
+
+ buff = (char *)malloc(len * sizeof(char));
+ if (!buff) return EINA_FALSE;
+
+ to = buff;
+ to_left = len;
+
+ if (!strcmp(from_type, type))
+ do_strcpy = EINA_TRUE;
+ else
+ {
+#ifdef HAVE_ICONV
+ conv = iconv_open(type, from_type);
+#endif
+ if (!conv)
+ {
+ free(buff);
+ return EINA_FALSE;
+ }
+ }
+
+ lptr = sptr = text_prop->value;
+ num = *count_ret = 0;
+ while (1)
+ {
+ if ((nitems == 0) || (*sptr == 0))
+ {
+ from = lptr;
+ from_left = sptr - lptr;
+ lptr = sptr;
+ if (do_strcpy)
+ {
+ int l = 0;
+
+ l = MIN(from_left, to_left);
+ strncpy(to, from, l);
+ from += len;
+ to += len;
+ from_left -= l;
+ to_left -= l;
+ ret = 0;
+ }
+ else
+ ret = iconv(conv, &from, &from_left, &to, &to_left);
+
+ if (ret < 0) continue;
+ num += ret;
+ (*count_ret)++;
+ if (nitems == 0) break;
+ lptr = ++sptr;
+ if (is_wide)
+ {
+ *((wchar_t *)to) = (wchar_t)0;
+ to += sizeof(wchar_t);
+ to_left -= sizeof(wchar_t);
+ }
+ else
+ {
+ *((char *)to) = '\0';
+ to++;
+ to_left--;
+ }
+ }
+ else
+ sptr++;
+
+ nitems--;
+ }
+
+#if HAVE_ICONV
+ if (!do_strcpy) iconv_close(conv);
+#endif
+
+ if (is_wide)
+ {
+ *((wchar_t *)to) = (wchar_t)0;
+ to_left -= sizeof(wchar_t);
+ }
+ else
+ {
+ *((char *)to) = '\0';
+ to_left--;
+ }
+
+ *list_ret =
+ _ecore_xcb_textlist_alloc_list(is_wide, *count_ret, (len - to_left));
+ if (*list_ret)
+ _ecore_xcb_textlist_copy_list(is_wide, buff, *list_ret, *count_ret);
+
+ free(buff);
+
+ return EINA_TRUE;
+}
+
+static int
+_ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide,
+ void *list,
+ int count)
+{
+ int len = 0;
+ char **mb;
+ wchar_t **wc;
+
+ if (!list) return 0;
+ if (is_wide)
+ {
+ wc = (wchar_t **)list;
+ for (; count-- > 0; wc++)
+ if (*wc) len += _ecore_xcb_textlist_get_wc_len(*wc) + 1;
+ len *= 5;
+ }
+ else
+ {
+ mb = (char **)list;
+ for (; count-- > 0; mb++)
+ if (*mb) len += strlen(*mb) + 1;
+ len *= 3;
+ }
+ len = (len / 2048 + 1) * 2048;
+ return len;
+}
+
+static int
+_ecore_xcb_textlist_get_wc_len(wchar_t *wstr)
+{
+ wchar_t *ptr;
+
+ ptr = wstr;
+ while (*ptr)
+ ptr++;
+
+ return ptr - wstr;
+}
+
+static void *
+_ecore_xcb_textlist_alloc_list(Eina_Bool is_wide,
+ int count,
+ int nitems)
+{
+ if (is_wide)
+ {
+ wchar_t **list;
+
+ list = (wchar_t **)malloc(count * sizeof(wchar_t *));
+ if (!list) return NULL;
+ *list = (wchar_t *)malloc(nitems * sizeof(wchar_t));
+ if (!*list)
+ {
+ free(list);
+ return NULL;
+ }
+ return *list;
+ }
+ else
+ {
+ char **list;
+
+ list = (char **)malloc(count * sizeof(char *));
+ if (!list) return NULL;
+ *list = (char *)malloc(nitems * sizeof(char));
+ if (!*list)
+ {
+ free(list);
+ return NULL;
+ }
+ return *list;
+ }
+}
+
+static void
+_ecore_xcb_textlist_copy_list(Eina_Bool is_wide,
+ void *text,
+ char **list,
+ int count)
+{
+ int len = 0;
+
+ if (is_wide)
+ {
+ wchar_t *txt, *str, **wlist;
+
+ txt = (wchar_t *)text;
+ wlist = (wchar_t **)list;
+ for (str = *wlist; count > 0; count--, wlist++)
+ {
+ _ecore_xcb_textlist_copy_wchar(str, txt);
+ *wlist = str;
+ len = (_ecore_xcb_textlist_len_wchar(str) + 1);
+ str += len;
+ txt += len;
+ }
+ }
+ else
+ {
+ char *txt, *str, **slist;
+
+ txt = (char *)text;
+ slist = (char **)list;
+ for (str = *slist; count > 0; count--, slist++)
+ {
+ strcpy(str, txt);
+ *slist = str;
+ len = strlen(str) + 1;
+ str += len;
+ txt += len;
+ }
+ }
+}
+
+static wchar_t *
+_ecore_xcb_textlist_copy_wchar(wchar_t *str1,
+ wchar_t *str2)
+{
+ wchar_t *tmp;
+
+ tmp = str1;
+ while ((*str1++ = *str2++))
+ ;
+ return tmp;
+}
+
+static int
+_ecore_xcb_textlist_len_wchar(wchar_t *str)
+{
+ wchar_t *ptr;
+
+ ptr = str;
+ while (*ptr)
+ ptr++;
+ return ptr - str;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_vsync.c b/src/lib/ecore_x/xcb/ecore_xcb_vsync.c
new file mode 100644
index 0000000000..7888796f9a
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_vsync.c
@@ -0,0 +1,375 @@
+#include "ecore_xcb_private.h"
+# include <fcntl.h>
+# include <dlfcn.h>
+# include <X11/Xlib-xcb.h>
+
+#define ECORE_XCB_VSYNC_DRI2 1
+#define DRM_EVENT_CONTEXT_VERSION 2
+
+#ifdef ECORE_XCB_VSYNC_DRI2
+
+/* relevant header bits of dri/drm inlined here to avoid needing external */
+/* headers to build drm */
+typedef unsigned int drm_magic_t;
+
+typedef enum
+{
+ DRM_VBLANK_ABSOLUTE = 0x00000000,
+ DRM_VBLANK_RELATIVE = 0x00000001,
+ DRM_VBLANK_EVENT = 0x04000000,
+ DRM_VBLANK_FLIP = 0x08000000,
+ DRM_VBLANK_NEXTONMISS = 0x10000000,
+ DRM_VBLANK_SECONDARY = 0x20000000,
+ DRM_VBLANK_SIGNAL = 0x40000000
+} drmVBlankSeqType;
+
+typedef struct _drmVBlankReq
+{
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ unsigned long signal;
+} drmVBlankReq;
+
+typedef struct _drmVBlankReply
+{
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ long tval_sec, tval_usec;
+} drmVBlankReply;
+
+typedef union _drmVBlank
+{
+ drmVBlankReq request;
+ drmVBlankReply reply;
+} drmVBlank;
+
+typedef struct _drmEventContext
+{
+ int version;
+ void (*vblank_handler)(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+ void (*page_flip_handler)(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+} drmEventContext;
+
+static int (*sym_drmClose)(int fd) = NULL;
+static int (*sym_drmGetMagic)(int fd,
+ drm_magic_t *magic) = NULL;
+static int (*sym_drmWaitVBlank)(int fd,
+ drmVBlank *vbl) = NULL;
+static int (*sym_drmHandleEvent)(int fd,
+ drmEventContext *evctx) = NULL;
+
+/* dri */
+static Bool (*sym_DRI2QueryExtension)(Display *display,
+ int *eventBase,
+ int *errorBase) = NULL;
+static Bool (*sym_DRI2QueryVersion)(Display *display,
+ int *major,
+ int *minor) = NULL;
+static Bool (*sym_DRI2Connect)(Display *display,
+ XID window,
+ char **driverName,
+ char **deviceName) = NULL;
+static Bool (*sym_DRI2Authenticate)(Display *display,
+ XID window,
+ drm_magic_t magic) = NULL;
+
+/* local function prototypes */
+static Eina_Bool _ecore_xcb_dri_link(void);
+static Eina_Bool _ecore_xcb_dri_start(void);
+static void _ecore_xcb_dri_shutdown(void);
+
+static Eina_Bool _ecore_xcb_dri_cb(void *data EINA_UNUSED,
+ Ecore_Fd_Handler *fdh EINA_UNUSED);
+static void _ecore_xcb_dri_tick_begin(void *data EINA_UNUSED);
+static void _ecore_xcb_dri_tick_end(void *data EINA_UNUSED);
+static void _ecore_xcb_dri_tick_schedule(void);
+static void _ecore_xcb_dri_vblank_handler(int fd EINA_UNUSED,
+ unsigned int frame EINA_UNUSED,
+ unsigned int sec EINA_UNUSED,
+ unsigned int usec EINA_UNUSED,
+ void *data EINA_UNUSED);
+
+/* local variables */
+static Ecore_X_Window _vsync_root = 0;
+static int _drm_fd = -1;
+static Ecore_Fd_Handler *_drm_fdh = NULL;
+static unsigned int _drm_magic = 0;
+static Eina_Bool _drm_event_busy = EINA_FALSE;
+static void *_drm_lib = NULL;
+static void *_dri_lib = NULL;
+static drmEventContext _drm_evctx;
+#endif
+
+void
+_ecore_xcb_dri_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+void
+_ecore_xcb_dri_finalize(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+EAPI Eina_Bool
+ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win)
+{
+#ifdef ECORE_XCB_VSYNC_DRI2
+ Ecore_X_Window root;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_VSYNC_DRI2
+ root = ecore_x_window_root_get(win);
+ if (root != _vsync_root)
+ {
+ _vsync_root = root;
+ if (_vsync_root)
+ {
+ if (!_ecore_xcb_dri_link())
+ {
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ return EINA_FALSE;
+ }
+ _ecore_xcb_dri_shutdown();
+ if (!_ecore_xcb_dri_start())
+ {
+ _vsync_root = 0;
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ return EINA_FALSE;
+ }
+ ecore_animator_custom_source_tick_begin_callback_set
+ (_ecore_xcb_dri_tick_begin, NULL);
+ ecore_animator_custom_source_tick_end_callback_set
+ (_ecore_xcb_dri_tick_end, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+ }
+ else
+ {
+ if (_drm_fd >= 0)
+ {
+ _ecore_xcb_dri_shutdown();
+ ecore_animator_custom_source_tick_begin_callback_set
+ (NULL, NULL);
+ ecore_animator_custom_source_tick_end_callback_set
+ (NULL, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ }
+ }
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ win = 0;
+#endif
+}
+
+/* local functions */
+#ifdef ECORE_XCB_VSYNC_DRI2
+static Eina_Bool
+_ecore_xcb_dri_link(void)
+{
+ const char *_drm_libs[] =
+ {
+ "libdrm.so.2",
+ "libdrm.so.1",
+ "libdrm.so.0",
+ "libdrm.so",
+ NULL,
+ };
+ const char *_dri_libs[] =
+ {
+ "libdri2.so.2",
+ "libdri2.so.1",
+ "libdri2.so.0",
+ "libdri2.so",
+ "libGL.so.4",
+ "libGL.so.3",
+ "libGL.so.2",
+ "libGL.so.1",
+ "libGL.so.0",
+ "libGL.so",
+ NULL,
+ };
+ int i = 0, fail = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+# define SYM(lib, xx) \
+ do { \
+ sym_## xx = dlsym(lib, #xx); \
+ if (!(sym_## xx)) { \
+ fprintf(stderr, "%s\n", dlerror()); \
+ fail = 1; \
+ } \
+ } while (0);
+
+ if (_drm_lib) return EINA_TRUE;
+
+ for (i = 0; _drm_libs[i]; i++)
+ {
+ _drm_lib = dlopen(_drm_libs[i], (RTLD_LOCAL | RTLD_LAZY));
+ if (_drm_lib)
+ {
+ fail = 0;
+ SYM(_drm_lib, drmClose);
+ SYM(_drm_lib, drmGetMagic);
+ SYM(_drm_lib, drmWaitVBlank);
+ SYM(_drm_lib, drmHandleEvent);
+ if (fail)
+ {
+ dlclose(_drm_lib);
+ _drm_lib = NULL;
+ }
+ else
+ break;
+ }
+ }
+ if (!_drm_lib) return EINA_FALSE;
+ for (i = 0; _dri_libs[i]; i++)
+ {
+ if ((_dri_lib = dlopen(_dri_libs[i], (RTLD_LOCAL | RTLD_LAZY))))
+ {
+ fail = 0;
+ SYM(_dri_lib, DRI2QueryExtension);
+ SYM(_dri_lib, DRI2QueryVersion);
+ SYM(_dri_lib, DRI2Connect);
+ SYM(_dri_lib, DRI2Authenticate);
+ if (fail)
+ {
+ dlclose(_dri_lib);
+ _dri_lib = NULL;
+ }
+ else
+ break;
+ }
+ }
+ if (!_dri_lib)
+ {
+ dlclose(_drm_lib);
+ _drm_lib = NULL;
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_xcb_dri_start(void)
+{
+ Ecore_X_Display *disp;
+ int _dri2_event = 0, _dri2_error = 0;
+ int _dri2_major = 0, _dri2_minor = 0;
+ char *device = NULL, *driver = NULL;
+
+ disp = ecore_x_display_get();
+ if (!sym_DRI2QueryExtension(disp, &_dri2_event, &_dri2_error))
+ return 0;
+ if (!sym_DRI2QueryVersion(disp, &_dri2_major, &_dri2_minor))
+ return 0;
+ if (_dri2_major < 2) return 0;
+ if (!sym_DRI2Connect(disp, _vsync_root, &driver, &device))
+ return 0;
+
+ _drm_fd = open(device, O_RDWR);
+ if (_drm_fd < 0) return 0;
+
+ sym_drmGetMagic(_drm_fd, &_drm_magic);
+ if (!sym_DRI2Authenticate(disp, _vsync_root, _drm_magic))
+ {
+ close(_drm_fd);
+ _drm_fd = -1;
+ return EINA_FALSE;
+ }
+
+ memset(&_drm_evctx, 0, sizeof(_drm_evctx));
+ _drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
+ _drm_evctx.vblank_handler = _ecore_xcb_dri_vblank_handler;
+ _drm_evctx.page_flip_handler = NULL;
+
+ _drm_fdh = ecore_main_fd_handler_add(_drm_fd, ECORE_FD_READ,
+ _ecore_xcb_dri_cb, NULL, NULL, NULL);
+ if (!_drm_fdh)
+ {
+ close(_drm_fd);
+ _drm_fd = -1;
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_ecore_xcb_dri_shutdown(void)
+{
+ if (_drm_fd >= 0)
+ {
+ close(_drm_fd);
+ _drm_fd = -1;
+ }
+ if (_drm_fdh)
+ {
+ ecore_main_fd_handler_del(_drm_fdh);
+ _drm_fdh = NULL;
+ }
+}
+
+static Eina_Bool
+_ecore_xcb_dri_cb(void *data EINA_UNUSED,
+ Ecore_Fd_Handler *fdh EINA_UNUSED)
+{
+ sym_drmHandleEvent(_drm_fd, &_drm_evctx);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_xcb_dri_tick_begin(void *data EINA_UNUSED)
+{
+ _drm_event_busy = EINA_TRUE;
+ _ecore_xcb_dri_tick_schedule();
+}
+
+static void
+_ecore_xcb_dri_tick_end(void *data EINA_UNUSED)
+{
+ _drm_event_busy = EINA_FALSE;
+}
+
+static void
+_ecore_xcb_dri_tick_schedule(void)
+{
+ drmVBlank vbl;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ vbl.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT);
+ vbl.request.sequence = 1;
+ vbl.request.signal = 0;
+
+ sym_drmWaitVBlank(_drm_fd, &vbl);
+}
+
+static void
+_ecore_xcb_dri_vblank_handler(int fd EINA_UNUSED,
+ unsigned int frame EINA_UNUSED,
+ unsigned int sec EINA_UNUSED,
+ unsigned int usec EINA_UNUSED,
+ void *data EINA_UNUSED)
+{
+ ecore_animator_custom_tick();
+ if (_drm_event_busy) _ecore_xcb_dri_tick_schedule();
+}
+
+#endif
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window.c b/src/lib/ecore_x/xcb/ecore_xcb_window.c
new file mode 100644
index 0000000000..f8405fe1ec
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_window.c
@@ -0,0 +1,2238 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_RENDER
+# include <xcb/render.h>
+#endif
+#ifdef ECORE_XCB_SHAPE
+# include <xcb/shape.h>
+#endif
+#ifdef ECORE_XCB_XPRINT
+#include <xcb/xprint.h>
+#endif
+
+/* local function prototypes */
+static Ecore_X_Window _ecore_xcb_window_argb_internal_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h,
+ uint8_t override_redirect,
+ uint8_t save_under);
+static Ecore_X_Window _ecore_xcb_window_at_xy_get(Ecore_X_Window base,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num);
+static int _ecore_xcb_window_modifiers_get(unsigned int state);
+static xcb_visualtype_t *_ecore_xcb_window_find_visual_by_id(xcb_visualid_t id);
+#ifdef ECORE_XCB_XPRINT
+static xcb_screen_t *_ecore_xcb_window_screen_of_display(int screen);
+#endif
+
+/* local variables */
+static int ignore_num = 0;
+static Ecore_X_Window *ignore_list = NULL;
+
+/* external variables */
+int _ecore_xcb_button_grabs_num = 0;
+int _ecore_xcb_key_grabs_num = 0;
+Ecore_X_Window *_ecore_xcb_button_grabs = NULL;
+Ecore_X_Window *_ecore_xcb_key_grabs = NULL;
+Eina_Bool (*_ecore_xcb_window_grab_replay_func)(void *data,
+ int type,
+ void *event);
+void *_ecore_xcb_window_grab_replay_data;
+
+/**
+ * @defgroup Ecore_X_Window_Create_Group X Window Creation Functions
+ *
+ * Functions that can be used to create an X window.
+ */
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win;
+ uint32_t mask, mask_list[9];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (parent == 0)
+ parent = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ /* NB: Order here is very important due to xcb_cw_t enum */
+ mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY |
+ XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE |
+ XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK |
+ XCB_CW_DONT_PROPAGATE);
+
+ mask_list[0] = XCB_BACK_PIXMAP_NONE;
+ mask_list[1] = 0;
+ mask_list[2] = XCB_GRAVITY_NORTH_WEST;
+ mask_list[3] = XCB_GRAVITY_NORTH_WEST;
+ mask_list[4] = XCB_BACKING_STORE_NOT_USEFUL;
+ mask_list[5] = 0;
+ mask_list[6] = 0;
+ mask_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE);
+ mask_list[8] = XCB_EVENT_MASK_NO_EVENT;
+
+ win = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT,
+ win, parent, x, y, w, h, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ XCB_COPY_FROM_PARENT, mask, mask_list);
+
+ if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root)
+ ecore_x_window_defaults_set(win);
+
+ return win;
+}
+
+/**
+ * Creates a window with the override redirect attribute set to @c True.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_override_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win;
+ uint32_t mask, mask_list[9];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (parent == 0)
+ parent = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ /* NB: Order here is very important due to xcb_cw_t enum */
+ mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY |
+ XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE |
+ XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK |
+ XCB_CW_DONT_PROPAGATE);
+
+ mask_list[0] = XCB_BACK_PIXMAP_NONE;
+ mask_list[1] = 0;
+ mask_list[2] = XCB_GRAVITY_NORTH_WEST;
+ mask_list[3] = XCB_GRAVITY_NORTH_WEST;
+ mask_list[4] = XCB_BACKING_STORE_NOT_USEFUL;
+ mask_list[5] = 1;
+ mask_list[6] = 0;
+ mask_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE);
+ mask_list[8] = XCB_EVENT_MASK_NO_EVENT;
+
+ win = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT,
+ win, parent, x, y, w, h, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ XCB_COPY_FROM_PARENT, mask, mask_list);
+
+ return win;
+}
+
+/**
+ * Creates a new input window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_input_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win;
+ uint32_t mask, mask_list[3];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__)
+ CHECK_XCB_CONN;
+
+ if (parent == 0)
+ parent = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ /* NB: Order here is very important due to xcb_cw_t enum */
+ mask = (XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK |
+ XCB_CW_DONT_PROPAGATE);
+
+ mask_list[0] = 1;
+ mask_list[1] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE);
+ mask_list[2] = XCB_EVENT_MASK_NO_EVENT;
+
+ win = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT,
+ win, parent, x, y, w, h, 0,
+ XCB_WINDOW_CLASS_INPUT_ONLY,
+ XCB_COPY_FROM_PARENT, mask, mask_list);
+
+ return win;
+}
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_manager_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0);
+
+ return win;
+}
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 0, 0);
+
+ return win;
+}
+
+/**
+ * Creates a window with the override redirect attribute set to @c True.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_override_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Ecore_X_Window win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0);
+
+ return win;
+}
+
+/**
+ * @defgroup Ecore_X_Window_Destroy_Group X Window Destroy Functions
+ *
+ * Functions to destroy X windows.
+ */
+
+/**
+ * Deletes the given window.
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Destroy_Group
+ */
+EAPI void
+ecore_x_window_free(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (win)
+ {
+ /* xcb_destroy_notify_event_t ev; */
+ /* Ecore_X_Window root; */
+
+ /* if (xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem == 1) */
+ /* root = ((xcb_screen_t *)_ecore_xcb_screen)->root; */
+ /* else */
+ /* { */
+ /* xcb_get_geometry_cookie_t cookie; */
+ /* xcb_get_geometry_reply_t *reply; */
+
+ /* cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); */
+ /* reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); */
+ /* if (!reply) return; */
+ /* root = reply->root; */
+ /* free(reply); */
+ /* } */
+
+ /* memset(&ev, 0, sizeof(xcb_destroy_notify_event_t)); */
+
+ /* ev.response_type = XCB_DESTROY_NOTIFY; */
+ /* ev.window = win; */
+ /* ev.event = root; */
+
+ /* xcb_send_event(_ecore_xcb_conn, 0, root, */
+ /* XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | */
+ /* XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, */
+ /* (const char *)&ev); */
+
+ xcb_destroy_window(_ecore_xcb_conn, win);
+// ecore_x_flush();
+ }
+}
+
+/**
+ * Sends a delete request to the given window.
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Destroy_Group
+ */
+EAPI void
+ecore_x_window_delete_request_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return;
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ XCB_EVENT_MASK_NO_EVENT,
+ ECORE_X_ATOM_WM_DELETE_WINDOW,
+ XCB_CURRENT_TIME, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_window_configure(Ecore_X_Window win,
+ Ecore_X_Window_Configure_Mask mask,
+ int x,
+ int y,
+ int w,
+ int h,
+ int border_width,
+ Ecore_X_Window sibling,
+ int stack_mode)
+{
+ uint16_t vmask = 0;
+ uint32_t vlist[7];
+ unsigned int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ if (mask & XCB_CONFIG_WINDOW_X)
+ {
+ vmask |= XCB_CONFIG_WINDOW_X;
+ vlist[i++] = x;
+ }
+ if (mask & XCB_CONFIG_WINDOW_Y)
+ {
+ vmask |= XCB_CONFIG_WINDOW_Y;
+ vlist[i++] = y;
+ }
+ if (mask & XCB_CONFIG_WINDOW_WIDTH)
+ {
+ vmask |= XCB_CONFIG_WINDOW_WIDTH;
+ vlist[i++] = w;
+ }
+ if (mask & XCB_CONFIG_WINDOW_HEIGHT)
+ {
+ vmask |= XCB_CONFIG_WINDOW_HEIGHT;
+ vlist[i++] = h;
+ }
+ if (mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
+ {
+ vmask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
+ vlist[i++] = border_width;
+ }
+ if (mask & XCB_CONFIG_WINDOW_SIBLING)
+ {
+ vmask |= XCB_CONFIG_WINDOW_SIBLING;
+ vlist[i++] = sibling;
+ }
+ if (mask & XCB_CONFIG_WINDOW_STACK_MODE)
+ {
+ vmask |= XCB_CONFIG_WINDOW_STACK_MODE;
+ vlist[i++] = stack_mode;
+ }
+
+ xcb_configure_window(_ecore_xcb_conn, win, vmask,
+ (const uint32_t *)&vlist);
+// ecore_x_flush();
+}
+
+/**
+ * @defgroup Ecore_X_Window_Geometry_Group X Window Geometry Functions
+ *
+ * Functions that change or retrieve the geometry of X windows.
+ */
+
+/**
+ * Moves a window to the position @p x, @p y.
+ *
+ * The position is relative to the upper left hand corner of the
+ * parent window.
+ *
+ * @param win The window to move.
+ * @param x X position.
+ * @param y Y position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_move(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ uint32_t list[2], mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y);
+ list[0] = x;
+ list[1] = y;
+
+ xcb_configure_window(_ecore_xcb_conn, win, mask,
+ (const uint32_t *)&list);
+// ecore_x_flush();
+}
+
+/**
+ * Resizes a window.
+ * @param win The window to resize.
+ * @param w New width of the window.
+ * @param h New height of the window.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_resize(Ecore_X_Window win,
+ int w,
+ int h)
+{
+ uint32_t list[2], mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ mask = (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT);
+ list[0] = w;
+ list[1] = h;
+
+ xcb_configure_window(_ecore_xcb_conn, win, mask,
+ (const uint32_t *)&list);
+// ecore_x_flush();
+}
+
+/**
+ * Moves and resizes a window.
+ * @param win The window to move and resize.
+ * @param x New X position of the window.
+ * @param y New Y position of the window.
+ * @param w New width of the window.
+ * @param h New height of the window.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_move_resize(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ uint32_t list[4], mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+ if (w < 1) w = 1;
+ if (h < 1) h = 1;
+
+ mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
+ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT);
+ list[0] = x;
+ list[1] = y;
+ list[2] = w;
+ list[3] = h;
+
+ xcb_configure_window(_ecore_xcb_conn, win, mask,
+ (const uint32_t *)&list);
+// ecore_x_flush();
+}
+
+/**
+ * Retrieves the width of the border of the given window.
+ * @param win The given window.
+ * @return Width of the border of @p win.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI int
+ecore_x_window_border_width_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!win) return 0;
+ return ecore_x_drawable_border_width_get(win);
+}
+
+/**
+ * Sets the width of the border of the given window.
+ * @param win The given window.
+ * @param width The new border width.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_border_width_set(Ecore_X_Window win,
+ int border_width)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) return;
+
+ list = border_width;
+
+ xcb_configure_window(_ecore_xcb_conn, win,
+ XCB_CONFIG_WINDOW_BORDER_WIDTH, &list);
+// ecore_x_flush();
+}
+
+/**
+ * @defgroup Ecore_X_Window_Z_Order_Group X Window Z Order Functions
+ *
+ * Functions that change the Z order of X windows.
+ */
+
+/**
+ * Raises the given window.
+ * @param win The window to raise.
+ * @ingroup Ecore_X_Window_Z_Order_Group
+ */
+EAPI void
+ecore_x_window_raise(Ecore_X_Window win)
+{
+ uint32_t list[] = { XCB_STACK_MODE_ABOVE };
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_configure_window(_ecore_xcb_conn, win,
+ XCB_CONFIG_WINDOW_STACK_MODE, list);
+// ecore_x_flush();
+}
+
+/**
+ * Lowers the given window.
+ * @param win The window to lower.
+ * @ingroup Ecore_X_Window_Z_Order_Group
+ */
+EAPI void
+ecore_x_window_lower(Ecore_X_Window win)
+{
+ uint32_t list[] = { XCB_STACK_MODE_BELOW };
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_configure_window(_ecore_xcb_conn, win,
+ XCB_CONFIG_WINDOW_STACK_MODE, list);
+// ecore_x_flush();
+}
+
+/**
+ * Retrieves the depth of the given window.
+ * @param win The given window.
+ * @return Depth of the window.
+ */
+EAPI int
+ecore_x_window_depth_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_drawable_depth_get(win);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions
+ *
+ * Functions that set window properties.
+ */
+
+/**
+ * Sets the default properties for the given window.
+ *
+ * The default properties set for the window are @c WM_CLIENT_MACHINE and
+ * @c _NET_WM_PID.
+ *
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Properties_Group
+ */
+EAPI void
+ecore_x_window_defaults_set(Ecore_X_Window win)
+{
+ char buff[MAXHOSTNAMELEN], **argv;
+ int argc;
+ pid_t pid;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ gethostname(buff, MAXHOSTNAMELEN);
+ buff[MAXHOSTNAMELEN - 1] = '\0';
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ ECORE_X_ATOM_WM_CLIENT_MACHINE, ECORE_X_ATOM_STRING,
+ 8, strlen(buff), buff);
+
+ pid = getpid();
+ ecore_x_netwm_pid_set(win, pid);
+ ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL);
+ ecore_app_args_get(&argc, &argv);
+ ecore_x_icccm_command_set(win, argc, argv);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions
+ *
+ * Functions to access and change the visibility of X windows.
+ */
+
+/**
+ * Shows a window.
+ *
+ * Synonymous to "mapping" a window in X Window System terminology.
+ *
+ * @param win The window to show.
+ * @ingroup Ecore_X_Window_Visibility
+ */
+EAPI void
+ecore_x_window_show(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (win)
+ xcb_map_window(_ecore_xcb_conn, win);
+}
+
+/**
+ * Hides a window.
+ *
+ * Synonymous to "unmapping" a window in X Window System terminology.
+ *
+ * @param win The window to hide.
+ * @ingroup Ecore_X_Window_Visibility
+ */
+EAPI void
+ecore_x_window_hide(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (win)
+ {
+ xcb_unmap_notify_event_t ev;
+ Ecore_X_Window root;
+
+ if (xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem == 1)
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ else
+ {
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+
+ cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ root = reply->root;
+ free(reply);
+ }
+
+ xcb_unmap_window(_ecore_xcb_conn, win);
+ memset(&ev, 0, sizeof(xcb_unmap_notify_event_t));
+
+ ev.response_type = XCB_UNMAP_NOTIFY;
+ ev.window = win;
+ ev.event = root;
+ ev.from_configure = 0;
+
+ xcb_send_event(_ecore_xcb_conn, 0, root,
+ (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT),
+ (const char *)&ev);
+
+// ecore_x_flush();
+ }
+}
+
+/**
+ * @defgroup Ecore_X_Window_Focus_Functions X Window Focus Functions
+ *
+ * Functions that give the focus to an X Window.
+ */
+
+/**
+ * Sets the focus to the window @p win.
+ * @param win The window to focus.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI void
+ecore_x_window_focus(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ xcb_set_input_focus(_ecore_xcb_conn,
+ XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME);
+// ecore_x_flush();
+}
+
+/**
+ * Sets the focus to the given window at a specific time.
+ * @param win The window to focus.
+ * @param t When to set the focus to the window.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI void
+ecore_x_window_focus_at_time(Ecore_X_Window win,
+ Ecore_X_Time time EINA_UNUSED)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ xcb_set_input_focus(_ecore_xcb_conn,
+ XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME);
+// ecore_x_flush();
+}
+
+/**
+ * @defgroup Ecore_X_Window_Parent_Group X Window Parent Functions
+ *
+ * Functions that retrieve or changes the parent window of a window.
+ */
+
+/**
+ * Moves a window to within another window at a given position.
+ * @param win The window to reparent.
+ * @param new_parent The new parent window.
+ * @param x X position within new parent window.
+ * @param y Y position within new parent window.
+ * @ingroup Ecore_X_Window_Parent_Group
+ */
+EAPI void
+ecore_x_window_reparent(Ecore_X_Window win,
+ Ecore_X_Window parent,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (parent == 0)
+ parent = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ xcb_reparent_window(_ecore_xcb_conn, win, parent, x, y);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_pixmap_set(Ecore_X_Window win,
+ Ecore_X_Pixmap pixmap)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = pixmap;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_BACK_PIXMAP, &list);
+// ecore_x_flush();
+}
+
+/**
+ * Sets the background color of the given window.
+ * @param win The given window
+ * @param r red value (0...65536, 16 bits)
+ * @param g green value (0...65536, 16 bits)
+ * @param b blue value (0...65536, 16 bits)
+ */
+EAPI void
+ecore_x_window_background_color_set(Ecore_X_Window win,
+ unsigned short red,
+ unsigned short green,
+ unsigned short blue)
+{
+ xcb_alloc_color_cookie_t cookie;
+ xcb_alloc_color_reply_t *reply;
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie =
+ xcb_alloc_color_unchecked(_ecore_xcb_conn,
+ ((xcb_screen_t *)_ecore_xcb_screen)->default_colormap,
+ red, green, blue);
+ reply = xcb_alloc_color_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return;
+ list = reply->pixel;
+ free(reply);
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_BACK_PIXEL, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_pixel_gravity_set(Ecore_X_Window win,
+ Ecore_X_Gravity gravity)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = gravity;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_BIT_GRAVITY, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_gravity_set(Ecore_X_Window win,
+ Ecore_X_Gravity gravity)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = gravity;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_WIN_GRAVITY, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_override_set(Ecore_X_Window win,
+ Eina_Bool override)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = override;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_OVERRIDE_REDIRECT, &list);
+// ecore_x_flush();
+}
+
+/**
+ * @brief Show the cursor on a window of type Ecore_X_Window.
+ * @param win The window for which the cursor will be showed.
+ * @param show Enables the show of the cursor on the window if equals EINA_TRUE, disables if equals EINA_FALSE.
+ */
+EAPI void
+ecore_x_window_cursor_show(Ecore_X_Window win,
+ Eina_Bool show)
+{
+ uint32_t list = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ if (!show)
+ {
+ Ecore_X_Cursor cursor;
+ Ecore_X_Pixmap p, m;
+ Ecore_X_GC gc;
+ xcb_point_t point;
+
+ p = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, 1, p, win, 1, 1);
+ m = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_pixmap(_ecore_xcb_conn, 1, m, win, 1, 1);
+ gc = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_gc(_ecore_xcb_conn, gc, win, 0, NULL);
+ xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_FOREGROUND, &list);
+ point.x = 0;
+ point.y = 0;
+ xcb_poly_point(_ecore_xcb_conn, XCB_COORD_MODE_ORIGIN,
+ win, gc, 1, &point);
+ xcb_free_gc(_ecore_xcb_conn, gc);
+
+ cursor = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_cursor(_ecore_xcb_conn, cursor,
+ p, m, 0, 0, 0, 0, 0, 0, 0, 0);
+ list = cursor;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_CURSOR, &list);
+
+ xcb_free_cursor(_ecore_xcb_conn, cursor);
+ xcb_free_pixmap(_ecore_xcb_conn, m);
+ xcb_free_pixmap(_ecore_xcb_conn, p);
+ }
+ else
+ {
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_CURSOR, &list);
+ }
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_cursor_set(Ecore_X_Window win,
+ Ecore_X_Cursor cursor)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = cursor;
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win, XCB_CW_CURSOR, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_container_manage(Ecore_X_Window win)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_client_manage(Ecore_X_Window win)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = (XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE);
+#endif
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_sniff(Ecore_X_Window win)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_PROPERTY_CHANGE);
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_client_sniff(Ecore_X_Window win)
+{
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ list = (XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE);
+
+ xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE);
+#endif
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_area_clear(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_clear_area(_ecore_xcb_conn, 0, win, x, y, w, h);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_area_expose(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_clear_area(_ecore_xcb_conn, 1, win, x, y, w, h);
+// ecore_x_flush();
+}
+
+EAPI void
+ecore_x_window_save_set_add(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_INSERT, win);
+}
+
+EAPI void
+ecore_x_window_save_set_del(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_DELETE, win);
+}
+
+/**
+ * gets the window that has focus.
+ * @return The window that has focus.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI Ecore_X_Window
+ecore_x_window_focus_get(void)
+{
+ xcb_get_input_focus_cookie_t cookie;
+ xcb_get_input_focus_reply_t *reply;
+ Ecore_X_Window focus = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_input_focus_unchecked(_ecore_xcb_conn);
+ reply = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ focus = reply->focus;
+ free(reply);
+ return focus;
+}
+
+EAPI int
+ecore_x_window_argb_get(Ecore_X_Window win)
+{
+ uint8_t ret = 0;
+#ifdef ECORE_XCB_RENDER
+ Ecore_X_Visual visual;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+// if (!win) return ret;
+
+#ifdef ECORE_XCB_RENDER
+ /* grab the window's visual */
+ visual = _ecore_xcb_window_visual_get(win);
+
+ /* check if this visual supports alpha */
+ ret = _ecore_xcb_render_visual_supports_alpha(visual);
+#endif
+
+ return ret;
+}
+
+EAPI Eina_Bool
+ecore_x_window_manage(Ecore_X_Window win)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ xcb_void_cookie_t change_cookie;
+ xcb_generic_error_t *err;
+ uint32_t list;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_window_attributes(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ ecore_x_sync(); // needed
+
+ list = (XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_RESIZE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ reply->your_event_mask);
+ free(reply);
+
+ change_cookie = xcb_change_window_attributes(_ecore_xcb_conn, win,
+ XCB_CW_EVENT_MASK, &list);
+
+ ecore_x_sync(); // needed
+
+ err = xcb_request_check(_ecore_xcb_conn, change_cookie);
+ if (err)
+ {
+ _ecore_xcb_error_handle(err);
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_window_attributes_get(Ecore_X_Window win,
+ Ecore_X_Window_Attributes *att_ret)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ xcb_get_geometry_cookie_t gcookie;
+ xcb_get_geometry_reply_t *greply;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ memset(att_ret, 0, sizeof(Ecore_X_Window_Attributes));
+
+ if (reply->map_state != XCB_MAP_STATE_UNMAPPED)
+ att_ret->visible = EINA_TRUE;
+
+ if (reply->map_state == XCB_MAP_STATE_VIEWABLE)
+ att_ret->viewable = EINA_TRUE;
+
+ if (reply->override_redirect)
+ att_ret->override = EINA_TRUE;
+
+ if (reply->_class == XCB_WINDOW_CLASS_INPUT_ONLY)
+ att_ret->input_only = EINA_TRUE;
+
+ if (reply->save_under)
+ att_ret->save_under = EINA_TRUE;
+
+ att_ret->event_mask.mine = reply->your_event_mask;
+ att_ret->event_mask.all = reply->all_event_masks;
+ att_ret->event_mask.no_propagate = reply->do_not_propagate_mask;
+ att_ret->window_gravity = reply->win_gravity;
+ att_ret->pixel_gravity = reply->bit_gravity;
+ att_ret->colormap = reply->colormap;
+ att_ret->visual = _ecore_xcb_window_find_visual_by_id(reply->visual);
+
+ free(reply);
+
+ gcookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win);
+ greply = xcb_get_geometry_reply(_ecore_xcb_conn, gcookie, NULL);
+ if (!greply) return EINA_TRUE;
+
+ /* xcb_translate_coordinates_reply_t *trans; */
+ /* xcb_query_tree_cookie_t tcookie; */
+ /* xcb_query_tree_reply_t *treply; */
+
+ /* tcookie = xcb_query_tree(_ecore_xcb_conn, win); */
+ /* treply = xcb_query_tree_reply(_ecore_xcb_conn, tcookie, NULL); */
+
+ /* trans = */
+ /* xcb_translate_coordinates_reply(_ecore_xcb_conn, */
+ /* xcb_translate_coordinates(_ecore_xcb_conn, */
+ /* win, treply->parent, greply->x, greply->y), NULL); */
+ /* free(treply); */
+
+ att_ret->root = greply->root;
+ att_ret->depth = greply->depth;
+// att_ret->x = trans->dst_x;
+// att_ret->y = trans->dst_y;
+ att_ret->x = greply->x;
+ att_ret->y = greply->y;
+ att_ret->w = greply->width;
+ att_ret->h = greply->height;
+ att_ret->border = greply->border_width;
+
+// free(trans);
+
+ free(greply);
+ return EINA_TRUE;
+}
+
+/**
+ * Retrieves the size of the given window.
+ * @param win The given window.
+ * @param w Pointer to an integer into which the width is to be stored.
+ * @param h Pointer to an integer into which the height is to be stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_size_get(Ecore_X_Window win,
+ int *width,
+ int *height)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ ecore_x_drawable_geometry_get(win, NULL, NULL, width, height);
+}
+
+/**
+ * Set if a window should be ignored.
+ * @param win The given window.
+ * @param ignore if to ignore
+ */
+EAPI void
+ecore_x_window_ignore_set(Ecore_X_Window win,
+ int ignore)
+{
+ int i = 0, j = 0, count = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (ignore)
+ {
+ if (ignore_list)
+ {
+ for (i = 0; i < ignore_num; i++)
+ if (win == ignore_list[i]) return;
+
+ ignore_list =
+ realloc(ignore_list, (ignore_num + 1) * sizeof(Ecore_X_Window));
+ if (!ignore_list) return;
+
+ ignore_list[ignore_num++] = win;
+ }
+ else
+ {
+ ignore_num = 0;
+ ignore_list = malloc(sizeof(Ecore_X_Window));
+ if (!ignore_list) return;
+ ignore_list[ignore_num++] = win;
+ }
+ }
+ else
+ {
+ if (!ignore_list) return;
+ for (count = ignore_num, i = 0, j = 0; i < count; i++)
+ {
+ if (win != ignore_list[i])
+ ignore_list[j++] = ignore_list[i];
+ else
+ ignore_num--;
+ }
+ if (ignore_num <= 0)
+ {
+ free(ignore_list);
+ ignore_list = NULL;
+ return;
+ }
+
+ ignore_list =
+ realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window));
+ }
+}
+
+/**
+ * Get the ignore list
+ * @param num number of windows in the list
+ * @return list of windows to ignore
+ */
+EAPI Ecore_X_Window *
+ecore_x_window_ignore_list(int *num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (num) *num = ignore_num;
+ return ignore_list;
+}
+
+/**
+ * Get a list of all the root windows on the server.
+ *
+ * @note The returned array will need to be freed after use.
+ * @param num_ret Pointer to integer to put number of windows returned in.
+ * @return An array of all the root windows. @c NULL is returned if memory
+ * could not be allocated for the list, or if @p num_ret is @c NULL.
+ */
+EAPI Ecore_X_Window *
+ecore_x_window_root_list(int *num_ret)
+{
+ xcb_screen_iterator_t iter;
+ uint8_t i, num;
+ Ecore_X_Window *roots = NULL;
+#ifdef ECORE_XCB_XPRINT
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!num_ret) return NULL;
+ if (num_ret) *num_ret = 0;
+
+ /* if (xcb_connection_has_error(_ecore_xcb_conn)) */
+ /* { */
+ /* DBG("XCB Connection Has Error !!!"); */
+ /* return NULL; */
+ /* } */
+
+ num = ecore_x_screen_count_get();
+
+#ifdef ECORE_XCB_XPRINT
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_x_print_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_x_print_print_query_screens_cookie_t cookie;
+ xcb_x_print_print_query_screens_reply_t *reply;
+
+ cookie = xcb_x_print_print_query_screens_unchecked(_ecore_xcb_conn);
+ reply =
+ xcb_x_print_print_query_screens_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ xcb_window_t *screens;
+ int psnum = 0, overlap = 0, j = 0, k = 0;
+
+ psnum = xcb_x_print_print_query_screens_roots_length(reply);
+ screens = xcb_x_print_print_query_screens_roots(reply);
+ for (i = 0; i < num; i++)
+ {
+ for (j = 0; j < psnum; j++)
+ {
+ xcb_screen_t *s;
+
+ if ((s = _ecore_xcb_window_screen_of_display(i)))
+ {
+ if (s->root == screens[j])
+ overlap++;
+ }
+ }
+ }
+ if (!(roots = malloc((num - overlap)
+ * sizeof(Ecore_X_Window)))) return NULL;
+ for (i = 0; i < num; i++)
+ {
+ Eina_Bool is_print = EINA_FALSE;
+
+ for (j = 0; j < psnum; j++)
+ {
+ xcb_screen_t *s;
+
+ if ((s = _ecore_xcb_window_screen_of_display(i)))
+ {
+ if (s->root == screens[j])
+ {
+ is_print = EINA_TRUE;
+ break;
+ }
+ }
+ }
+ if (!is_print)
+ {
+ xcb_screen_t *s;
+
+ if ((s = _ecore_xcb_window_screen_of_display(i)))
+ {
+ roots[k] = s->root;
+ k++;
+ }
+ }
+ }
+ if (num_ret) *num_ret = k;
+ free(reply);
+ }
+ else
+ {
+ /* Fallback to default method */
+ iter =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL;
+ if (num_ret) *num_ret = num;
+ for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
+ roots[i] = iter.data->root;
+ }
+ }
+ else
+ {
+ /* Fallback to default method */
+ iter =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL;
+ if (num_ret) *num_ret = num;
+ for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
+ roots[i] = iter.data->root;
+ }
+#else
+ iter =
+ xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL;
+ if (num_ret) *num_ret = num;
+ for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
+ roots[i] = iter.data->root;
+#endif
+
+ return roots;
+}
+
+EAPI Ecore_X_Window *
+ecore_x_window_children_get(Ecore_X_Window win,
+ int *num)
+{
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ Ecore_X_Window *windows = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+ cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+
+ if (num) *num = reply->children_len;
+ if (reply->children_len > 0)
+ {
+ windows = malloc(sizeof(Ecore_X_Window) * reply->children_len);
+ if (windows)
+ {
+ unsigned int i = 0;
+ xcb_window_t *w;
+
+ w = xcb_query_tree_children(reply);
+ for (i = 0; i < reply->children_len; i++)
+ windows[i] = w[i];
+ }
+ }
+
+ free(reply);
+ return windows;
+}
+
+/**
+ * Retrieves the root window a given window is on.
+ * @param win The window to get the root window of
+ * @return The root window of @p win
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_root_get(Ecore_X_Window win)
+{
+ xcb_get_geometry_cookie_t gcookie;
+ xcb_get_geometry_reply_t *greply;
+ Ecore_X_Window window = 0;
+
+ /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
+ CHECK_XCB_CONN;
+
+ gcookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win);
+ greply = xcb_get_geometry_reply(_ecore_xcb_conn, gcookie, NULL);
+ if (!greply) return 0;
+ window = greply->root;
+ free(greply);
+
+ return window;
+}
+
+EAPI Ecore_X_Window
+ecore_x_window_root_first_get(void)
+{
+ return ((xcb_screen_t *)_ecore_xcb_screen)->root;
+}
+
+/**
+ * Retrieves the geometry of the given window.
+ *
+ * Note that the x & y coordingates are relative to your parent. In
+ * particular for reparenting window managers - relative to you window border.
+ * If you want screen coordinates either walk the window tree to the root,
+ * else for ecore_evas applications see ecore_evas_geometry_get(). Elementary
+ * applications can use elm_win_screen_position_get().
+ *
+ * @param win The given window.
+ * @param x Pointer to an integer in which the X position is to be stored.
+ * @param y Pointer to an integer in which the Y position is to be stored.
+ * @param w Pointer to an integer in which the width is to be stored.
+ * @param h Pointer to an integer in which the height is to be stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+ ecore_x_drawable_geometry_get(win, x, y, w, h);
+}
+
+/**
+ * Retrieves the top, visible window at the given location.
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @return The window at that position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_get(int x,
+ int y)
+{
+ Ecore_X_Window root, win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ ecore_x_grab();
+ win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, NULL, 0);
+ ecore_x_ungrab();
+
+ return win ? win : root;
+}
+
+/**
+ * Retrieves the top, visible window at the given location,
+ * but skips the windows in the list.
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @param skip The list of windows to be skipped.
+ * @param skip_num The number of windows to be skipped.
+ * @return The window at that position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_with_skip_get(int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Ecore_X_Window root, win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ ecore_x_grab();
+ win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, skip, skip_num);
+ ecore_x_ungrab();
+
+ return win ? win : root;
+}
+
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_begin_get(Ecore_X_Window begin,
+ int x,
+ int y)
+{
+ Ecore_X_Window win = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ ecore_x_grab();
+ win = _ecore_xcb_window_at_xy_get(begin, 0, 0, x, y, NULL, 0);
+ ecore_x_ungrab();
+
+ return win ? win : begin;
+}
+
+/**
+ * Retrieves the parent window of the given window.
+ * @param win The given window.
+ * @return The parent window of @p win.
+ * @ingroup Ecore_X_Window_Parent_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_parent_get(Ecore_X_Window win)
+{
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ Ecore_X_Window window = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+// if (!win) return 0;
+ cookie = xcb_query_tree(_ecore_xcb_conn, win);
+ reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ window = reply->parent;
+ free(reply);
+
+ return window;
+}
+
+/**
+ * Finds out whether the given window is currently visible.
+ * @param win The given window.
+ * @return 1 if the window is visible, otherwise 0.
+ * @ingroup Ecore_X_Window_Visibility_Group
+ */
+EAPI int
+ecore_x_window_visible_get(Ecore_X_Window win)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ int ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ if (reply->map_state == XCB_MAP_STATE_VIEWABLE)
+ ret = EINA_TRUE;
+
+ free(reply);
+ return ret;
+}
+
+EAPI void
+ecore_x_window_button_grab(Ecore_X_Window win,
+ int button,
+ Ecore_X_Event_Mask mask,
+ int mod,
+ int any_mod)
+{
+ int i = 0;
+ uint16_t m, locks[8], ev;
+ uint8_t b;
+ Ecore_X_Window *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ b = button;
+ if (b == 0)
+ b = XCB_BUTTON_INDEX_ANY;
+
+ m = _ecore_xcb_window_modifiers_get(mod);
+ if (any_mod) m = XCB_MOD_MASK_ANY;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+
+ ev = mask;
+ for (i = 0; i < 8; i++)
+ xcb_grab_button(_ecore_xcb_conn, 0, win, ev,
+ XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
+ XCB_NONE, XCB_NONE, b, m | locks[i]);
+
+ _ecore_xcb_button_grabs_num++;
+ t = realloc(_ecore_xcb_button_grabs,
+ _ecore_xcb_button_grabs_num * sizeof(Ecore_X_Window));
+ if (!t) return;
+
+ _ecore_xcb_button_grabs = t;
+ _ecore_xcb_button_grabs[_ecore_xcb_button_grabs_num - 1] = win;
+}
+
+EAPI void
+ecore_x_window_button_ungrab(Ecore_X_Window win,
+ int button,
+ int mod,
+ int any_mod)
+{
+ int i = 0;
+ uint16_t m = 0, locks[8];
+ uint8_t b;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ b = button;
+ if (b == 0) b = XCB_BUTTON_INDEX_ANY;
+
+ m = _ecore_xcb_window_modifiers_get(mod);
+ if (any_mod) m = XCB_MOD_MASK_ANY;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+
+ for (i = 0; i < 8; i++)
+ xcb_ungrab_button(_ecore_xcb_conn, b, win, m | locks[i]);
+
+ _ecore_xcb_sync_magic_send(1, win);
+}
+
+EAPI void
+ecore_x_window_key_grab(Ecore_X_Window win,
+ const char *key,
+ int mod,
+ int any_mod)
+{
+ xcb_keycode_t keycode = XCB_NO_SYMBOL;
+ uint16_t m = 0, locks[8];
+ int i = 0;
+ Ecore_X_Window *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ keycode = _ecore_xcb_keymap_string_to_keycode(key);
+ if (keycode == XCB_NO_SYMBOL) return;
+
+ m = _ecore_xcb_window_modifiers_get(mod);
+ if (any_mod) m = XCB_MOD_MASK_ANY;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+
+ for (i = 0; i < 8; i++)
+ xcb_grab_key(_ecore_xcb_conn, 0, win, m | locks[i],
+ keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+ _ecore_xcb_key_grabs_num++;
+ t = realloc(_ecore_xcb_key_grabs,
+ _ecore_xcb_key_grabs_num * sizeof(Ecore_X_Window));
+ if (!t) return;
+ _ecore_xcb_key_grabs = t;
+ _ecore_xcb_key_grabs[_ecore_xcb_key_grabs_num - 1] = win;
+}
+
+EAPI void
+ecore_x_window_key_ungrab(Ecore_X_Window win,
+ const char *key,
+ int mod,
+ int any_mod)
+{
+ xcb_keycode_t keycode = XCB_NO_SYMBOL;
+ uint16_t m = 0, locks[8];
+ int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ keycode = _ecore_xcb_keymap_string_to_keycode(key);
+ if (keycode == XCB_NO_SYMBOL) return;
+
+ m = _ecore_xcb_window_modifiers_get(mod);
+ if (any_mod) m = XCB_MOD_MASK_ANY;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+
+ for (i = 0; i < 8; i++)
+ xcb_ungrab_key(_ecore_xcb_conn, keycode, win, m | locks[i]);
+
+ _ecore_xcb_sync_magic_send(2, win);
+}
+
+/* local functions */
+Ecore_X_Window
+_ecore_xcb_window_root_of_screen_get(int screen)
+{
+ xcb_screen_iterator_t iter;
+
+ CHECK_XCB_CONN;
+ iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ for (; iter.rem; --screen, xcb_screen_next(&iter))
+ if (screen == 0)
+ {
+ xcb_screen_t *s;
+
+ if ((s = iter.data))
+ return s->root;
+ }
+ return 0;
+}
+
+static Ecore_X_Window
+_ecore_xcb_window_argb_internal_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h,
+ uint8_t override_redirect,
+ uint8_t save_under)
+{
+ Ecore_X_Window win = 0;
+#ifdef ECORE_XCB_RENDER
+ uint32_t value_list[10];
+ uint32_t value_mask;
+ uint32_t vis;
+ Ecore_X_Colormap colormap;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_RENDER
+ if (parent == 0)
+ parent = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ vis =
+ _ecore_xcb_render_find_visual_id(XCB_RENDER_PICT_TYPE_DIRECT, EINA_TRUE);
+
+ colormap = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_colormap(_ecore_xcb_conn, XCB_COLORMAP_ALLOC_NONE,
+ colormap, parent, vis);
+
+ value_mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY |
+ XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE |
+ XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER |
+ XCB_CW_EVENT_MASK | XCB_CW_DONT_PROPAGATE | XCB_CW_COLORMAP);
+
+ value_list[0] = XCB_BACK_PIXMAP_NONE;
+ value_list[1] = 0;
+ value_list[2] = XCB_GRAVITY_NORTH_WEST;
+ value_list[3] = XCB_GRAVITY_NORTH_WEST;
+ value_list[4] = XCB_BACKING_STORE_NOT_USEFUL;
+ value_list[5] = override_redirect;
+ value_list[6] = save_under;
+ value_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_FOCUS_CHANGE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_COLOR_MAP_CHANGE);
+ value_list[8] = XCB_EVENT_MASK_NO_EVENT;
+ value_list[9] = colormap;
+
+ win = xcb_generate_id(_ecore_xcb_conn);
+ xcb_create_window(_ecore_xcb_conn, 32, win, parent, x, y, w, h, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, vis, value_mask,
+ value_list);
+
+ xcb_free_colormap(_ecore_xcb_conn, colormap);
+
+ if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root)
+ ecore_x_window_defaults_set(win);
+#endif
+
+ return win;
+}
+
+static Ecore_X_Window
+_ecore_xcb_window_at_xy_get(Ecore_X_Window base,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ Ecore_X_Window *windows = NULL;
+ int wx, wy, ww, wh, num, i = 0;
+ Eina_Bool skipit = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!ecore_x_window_visible_get(base)) return 0;
+
+ ecore_x_window_geometry_get(base, &wx, &wy, &ww, &wh);
+ wx += bx;
+ wy += by;
+
+ if (!((x >= wx) && (y >= wy) && (x < (wx + ww)) && (y < (wy + wh))))
+ return 0;
+
+ cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, base);
+ reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+
+ num = reply->children_len;
+ windows = xcb_query_tree_children(reply);
+
+ for (i = (num - 1); i >= 0; --i)
+ {
+ skipit = EINA_FALSE;
+
+ if (skip)
+ {
+ int j = 0;
+
+ for (j = 0; j < skip_num; j++)
+ {
+ if (windows[i] == skip[j])
+ {
+ skipit = EINA_TRUE;
+ goto onward;
+ }
+ }
+ }
+onward:
+ if (!skipit)
+ {
+ Ecore_X_Window child = 0;
+
+ child =
+ _ecore_xcb_window_at_xy_get(windows[i],
+ wx, wy, x, y, skip, skip_num);
+ if (child)
+ {
+ if (reply) free(reply);
+ return child;
+ }
+ }
+ }
+
+ if (reply) free(reply);
+ return base;
+}
+
+Ecore_X_Visual
+_ecore_xcb_window_visual_get(Ecore_X_Window win)
+{
+ xcb_get_window_attributes_cookie_t cookie;
+ xcb_get_window_attributes_reply_t *reply;
+ Ecore_X_Visual visual = 0;
+
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_window_attributes(_ecore_xcb_conn, win);
+ reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ visual = _ecore_xcb_window_find_visual_by_id(reply->visual);
+ free(reply);
+
+ return visual;
+}
+
+void
+_ecore_xcb_window_button_grab_remove(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (_ecore_xcb_button_grabs_num > 0)
+ {
+ int i = 0, shuffle = 0;
+
+ for (i = 0; i < _ecore_xcb_button_grabs_num; i++)
+ {
+ if (shuffle)
+ _ecore_xcb_button_grabs[i - 1] = _ecore_xcb_button_grabs[i];
+
+ if ((!shuffle) && (_ecore_xcb_button_grabs[i] == win))
+ shuffle = 1;
+ }
+
+ if (shuffle)
+ {
+ Ecore_X_Window *t;
+
+ _ecore_xcb_button_grabs_num--;
+ if (_ecore_xcb_button_grabs_num <= 0)
+ {
+ free(_ecore_xcb_button_grabs);
+ _ecore_xcb_button_grabs = NULL;
+ return;
+ }
+
+ t = realloc(_ecore_xcb_button_grabs,
+ _ecore_xcb_button_grabs_num * sizeof(Ecore_X_Window));
+ if (!t) return;
+ _ecore_xcb_button_grabs = t;
+ }
+ }
+}
+
+void
+_ecore_xcb_window_key_grab_remove(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (_ecore_xcb_key_grabs_num > 0)
+ {
+ int i = 0, shuffle = 0;
+
+ for (i = 0; i < _ecore_xcb_key_grabs_num; i++)
+ {
+ if (shuffle)
+ _ecore_xcb_key_grabs[i - 1] = _ecore_xcb_key_grabs[i];
+
+ if ((!shuffle) && (_ecore_xcb_key_grabs[i] == win))
+ shuffle = 1;
+ }
+
+ if (shuffle)
+ {
+ Ecore_X_Window *t;
+
+ _ecore_xcb_key_grabs_num--;
+ if (_ecore_xcb_key_grabs_num <= 0)
+ {
+ free(_ecore_xcb_key_grabs);
+ _ecore_xcb_key_grabs = NULL;
+ return;
+ }
+
+ t = realloc(_ecore_xcb_key_grabs,
+ _ecore_xcb_key_grabs_num * sizeof(Ecore_X_Window));
+ if (!t) return;
+ _ecore_xcb_key_grabs = t;
+ }
+ }
+}
+
+void
+_ecore_xcb_window_grab_allow_events(Ecore_X_Window event_win,
+ Ecore_X_Window child_win,
+ int type,
+ void *event,
+ Ecore_X_Time timestamp)
+{
+ int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ for (i = 0; i < _ecore_xcb_button_grabs_num; i++)
+ {
+ if ((_ecore_xcb_button_grabs[i] == event_win) ||
+ (_ecore_xcb_button_grabs[i] == child_win))
+ {
+ Eina_Bool replay = EINA_FALSE;
+
+ if (_ecore_xcb_window_grab_replay_func)
+ {
+ replay =
+ _ecore_xcb_window_grab_replay_func(_ecore_xcb_window_grab_replay_data,
+ type, event);
+ }
+ if (replay)
+ {
+ xcb_allow_events(_ecore_xcb_conn,
+ XCB_ALLOW_REPLAY_POINTER, timestamp);
+ }
+ else
+ {
+ xcb_allow_events(_ecore_xcb_conn,
+ XCB_ALLOW_ASYNC_POINTER, timestamp);
+ }
+ break;
+ }
+ }
+}
+
+static int
+_ecore_xcb_window_modifiers_get(unsigned int state)
+{
+ int xmodifiers = 0;
+
+ if (state & ECORE_EVENT_MODIFIER_SHIFT)
+ xmodifiers |= ECORE_X_MODIFIER_SHIFT;
+ if (state & ECORE_EVENT_MODIFIER_CTRL)
+ xmodifiers |= ECORE_X_MODIFIER_CTRL;
+ if (state & ECORE_EVENT_MODIFIER_ALT)
+ xmodifiers |= ECORE_X_MODIFIER_ALT;
+ if (state & ECORE_EVENT_MODIFIER_WIN)
+ xmodifiers |= ECORE_X_MODIFIER_WIN;
+ if (state & ECORE_EVENT_MODIFIER_ALTGR)
+ xmodifiers |= ECORE_X_MODIFIER_ALTGR;
+ if (state & ECORE_EVENT_LOCK_SCROLL)
+ xmodifiers |= ECORE_X_LOCK_SCROLL;
+ if (state & ECORE_EVENT_LOCK_NUM)
+ xmodifiers |= ECORE_X_LOCK_NUM;
+ if (state & ECORE_EVENT_LOCK_CAPS)
+ xmodifiers |= ECORE_X_LOCK_CAPS;
+ if (state & ECORE_EVENT_LOCK_SHIFT)
+ xmodifiers |= ECORE_X_LOCK_SHIFT;
+
+ return xmodifiers;
+}
+
+static xcb_visualtype_t *
+_ecore_xcb_window_find_visual_by_id(xcb_visualid_t id)
+{
+ xcb_depth_iterator_t diter;
+ xcb_visualtype_iterator_t viter;
+
+ CHECK_XCB_CONN;
+ diter = xcb_screen_allowed_depths_iterator(_ecore_xcb_screen);
+ for (; diter.rem; xcb_depth_next(&diter))
+ {
+ viter = xcb_depth_visuals_iterator(diter.data);
+ for (; viter.rem; xcb_visualtype_next(&viter))
+ {
+ if (viter.data->visual_id == id)
+ return viter.data;
+ }
+ }
+ return 0;
+}
+
+#ifdef ECORE_XCB_XPRINT
+static xcb_screen_t *
+_ecore_xcb_window_screen_of_display(int screen)
+{
+ xcb_screen_iterator_t iter;
+
+ CHECK_XCB_CONN;
+ iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
+ for (; iter.rem; --screen, xcb_screen_next(&iter))
+ if (screen == 0)
+ return iter.data;
+
+ return NULL;
+}
+
+#endif
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c b/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c
new file mode 100644
index 0000000000..e00fdc1963
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c
@@ -0,0 +1,720 @@
+#include "ecore_xcb_private.h"
+#include <xcb/xcb_icccm.h>
+
+EAPI int
+ecore_x_window_prop_card32_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int *val,
+ unsigned int len)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom,
+ ECORE_X_ATOM_CARDINAL, 0, 0x7fffffff);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return -1;
+
+ if ((reply->type != ECORE_X_ATOM_CARDINAL) || (reply->format != 32))
+ num = -1;
+ else if (reply->value_len == 0)
+ num = 0;
+ else
+ {
+ if (reply->value_len < len)
+ len = reply->value_len;
+
+ if (val)
+ {
+ unsigned int i = 0;
+ unsigned char *v;
+
+ v = xcb_get_property_value(reply);
+ for (i = 0; i < len; i++)
+ val[i] = ((uint32_t *)v)[i];
+ num = len;
+ }
+ }
+
+ if (reply) free(reply);
+ return num;
+}
+
+EAPI void
+ecore_x_window_prop_card32_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int *val,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#if SIZEOF_INT == SIZEOF_LONG
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom,
+ ECORE_X_ATOM_CARDINAL, 32, num, (unsigned char *)val);
+// ecore_x_flush();
+#else
+ long *v2;
+ unsigned int i;
+
+ v2 = malloc(num * sizeof(long));
+ if (!v2) return;
+ for (i = 0; i < num; i++)
+ v2[i] = val[i];
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom,
+ ECORE_X_ATOM_CARDINAL, 32, num, (unsigned char *)v2);
+ free(v2);
+// ecore_x_flush();
+#endif
+}
+
+EAPI int
+ecore_x_window_prop_card32_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int **list)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int num = -1;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (list) *list = NULL;
+
+ cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom,
+ XCB_ATOM_CARDINAL, 0, 0x7fffffff);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return -1;
+
+ if ((reply->type != XCB_ATOM_CARDINAL) || (reply->format != 32))
+ num = -1;
+ else if ((reply->value_len == 0) || (!xcb_get_property_value(reply)))
+ num = 0;
+ else
+ {
+ num = reply->value_len;
+ if (list)
+ {
+ unsigned int *val;
+ void *data;
+ int i = 0;
+
+ val = malloc(num * sizeof(unsigned int));
+ if (!val)
+ {
+ free(reply);
+ return -1;
+ }
+ data = xcb_get_property_value(reply);
+ for (i = 0; i < num; i++)
+ val[i] = ((uint32_t *)data)[i];
+ *list = val;
+ }
+ }
+
+ free(reply);
+ return num;
+}
+
+EAPI int
+ecore_x_window_prop_atom_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom *list,
+ unsigned int len)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_ATOM, list, len);
+}
+
+EAPI void
+ecore_x_window_prop_atom_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom *list,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ /* xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, */
+ /* ECORE_X_ATOM_ATOM, 32, num, list); */
+ ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_ATOM, list, num);
+}
+
+EAPI void
+ecore_x_window_prop_xid_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID *xids,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#if SIZEOF_INT == SIZEOF_LONG
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom,
+ type, 32, num, (unsigned char *)xids);
+// ecore_x_flush();
+#else
+ long *v2;
+ unsigned int i;
+
+ v2 = malloc(num * sizeof(long));
+ if (!v2) return;
+ for (i = 0; i < num; i++)
+ v2[i] = xids[i];
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom,
+ type, 32, num, (unsigned char *)v2);
+ free(v2);
+// ecore_x_flush();
+#endif
+}
+
+EAPI int
+ecore_x_window_prop_xid_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID *xids,
+ unsigned int len)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ num = len;
+ cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, type,
+ 0, 0x7fffffff);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return -1;
+
+ if ((reply->type != type) || (reply->format != 32))
+ num = -1;
+ else if (reply->value_len == 0)
+ num = 0;
+ else
+ {
+ unsigned int i = 0;
+ unsigned char *v;
+
+ if (reply->value_len < len)
+ len = reply->value_len;
+
+ v = xcb_get_property_value(reply);
+ for (i = 0; i < len; i++)
+ xids[i] = ((uint32_t *)v)[i];
+
+ num = len;
+ }
+
+ if (reply) free(reply);
+ return num;
+}
+
+EAPI void
+ecore_x_window_prop_string_set(Ecore_X_Window win,
+ Ecore_X_Atom type,
+ const char *str)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, type,
+ ECORE_X_ATOM_UTF8_STRING, 8, strlen(str), str);
+// ecore_x_flush();
+}
+
+EAPI char *
+ecore_x_window_prop_string_get(Ecore_X_Window win,
+ Ecore_X_Atom type)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ char *str = NULL;
+ int len = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ cookie =
+ xcb_get_property_unchecked(_ecore_xcb_conn, 0,
+ win ? win : ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ type, XCB_GET_PROPERTY_TYPE_ANY, 0, 1000000L);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+
+ len = ((reply->value_len * reply->format) / 8);
+ str = (char *)malloc((len + 1) * sizeof(char));
+ memcpy(str, xcb_get_property_value(reply), len);
+ str[len] = '\0';
+
+ if (reply->type != ECORE_X_ATOM_UTF8_STRING)
+ {
+ Ecore_Xcb_Textproperty prop;
+ int count = 0;
+ char **list = NULL;
+ Eina_Bool ret = EINA_FALSE;
+
+ prop.value = strdup(str);
+ prop.nitems = len;
+ prop.encoding = reply->type;
+
+#ifdef HAVE_ICONV
+ ret = _ecore_xcb_utf8_textproperty_to_textlist(&prop, &list, &count);
+#else
+ ret = _ecore_xcb_mb_textproperty_to_textlist(&prop, &list, &count);
+#endif
+ if (ret)
+ {
+ if (count > 0)
+ str = strdup(list[0]);
+ else
+ str = strdup((char *)prop.value);
+
+ if (list) free(list);
+ }
+ else
+ str = strdup((char *)prop.value);
+ }
+
+ free(reply);
+ return str;
+}
+
+EAPI int
+ecore_x_window_prop_window_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window *list,
+ unsigned int len)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_WINDOW, list, len);
+}
+
+EAPI void
+ecore_x_window_prop_window_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window *list,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_WINDOW, list, num);
+}
+
+EAPI int
+ecore_x_window_prop_window_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window **plst)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_WINDOW, plst);
+}
+
+EAPI Ecore_X_Atom
+ecore_x_window_prop_any_type(void)
+{
+ return XCB_ATOM_ANY;
+}
+
+EAPI void
+ecore_x_window_prop_property_del(Ecore_X_Window win,
+ Ecore_X_Atom property)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ xcb_delete_property(_ecore_xcb_conn, win, property);
+}
+
+EAPI void
+ecore_x_window_prop_property_set(Ecore_X_Window win,
+ Ecore_X_Atom property,
+ Ecore_X_Atom type,
+ int size,
+ void *data,
+ int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (win == 0)
+ win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ if (size != 32)
+ {
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ property, type, size, num, (unsigned char *)data);
+// ecore_x_flush();
+ }
+ else
+ {
+ uint32_t *dat;
+ int i = 0, *ptr;
+
+ dat = malloc(sizeof(uint32_t) * num);
+ if (dat)
+ {
+ for (ptr = (int *)data, i = 0; i < num; i++)
+ dat[i] = ptr[i];
+ xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win,
+ property, type, size, num,
+ (unsigned char *)dat);
+ free(dat);
+// ecore_x_flush();
+ }
+ }
+}
+
+EAPI int
+ecore_x_window_prop_property_get(Ecore_X_Window win,
+ Ecore_X_Atom property,
+ Ecore_X_Atom type,
+ int size,
+ unsigned char **data,
+ int *num)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int format = 0;
+ unsigned int i = 0;
+ void *value;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+
+ if (data)
+ *data = NULL;
+ else
+ return 0;
+
+ if (win == 0)
+ win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ cookie =
+ xcb_get_property_unchecked(_ecore_xcb_conn, 0, win,
+ property, type, 0, UINT_MAX);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ if ((reply->format != size) || (reply->value_len == 0))
+ {
+ free(reply);
+ return 0;
+ }
+
+ if (!(*data = malloc(reply->value_len * reply->format / 8)))
+ {
+ free(reply);
+ return 0;
+ }
+
+ value = xcb_get_property_value(reply);
+ switch (reply->format)
+ {
+ case 8:
+ for (i = 0; i < reply->value_len; i++)
+ (*data)[i] = ((unsigned char *)value)[i];
+ break;
+
+ case 16:
+ for (i = 0; i < reply->value_len; i++)
+ ((unsigned short *)*data)[i] = ((unsigned short *)value)[i];
+ break;
+
+ case 32:
+ for (i = 0; i < reply->value_len; i++)
+ ((unsigned int *)*data)[i] = ((uint32_t *)value)[i];
+ break;
+ }
+
+ if (num) *num = reply->value_len;
+ format = reply->format;
+ free(reply);
+ return format;
+}
+
+EAPI int
+ecore_x_window_prop_atom_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom **list)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_ATOM, list);
+}
+
+EAPI void
+ecore_x_window_prop_atom_list_change(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom item,
+ int op)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_xid_list_change(win, atom, ECORE_X_ATOM_ATOM, item, op);
+}
+
+EAPI int
+ecore_x_window_prop_xid_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID **xids)
+{
+ xcb_get_property_cookie_t cookie;
+ xcb_get_property_reply_t *reply;
+ int num = -1;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (xids) *xids = NULL;
+
+ cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, type,
+ 0, 0x7fffffff);
+ reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return -1;
+
+ if ((reply->type != type) || (reply->format != 32))
+ num = -1;
+ else if ((reply->value_len == 0) || (!xcb_get_property_value(reply)))
+ num = 0;
+ else
+ {
+ Ecore_X_Atom *alst;
+ void *val;
+
+ num = xcb_get_property_value_length(reply);
+ val = xcb_get_property_value(reply);
+ alst = malloc(num * sizeof(Ecore_X_ID));
+ if (alst)
+ {
+ int i = 0;
+
+ for (i = 0; i < num; i++)
+ alst[i] = ((uint32_t *)val)[i];
+ *xids = alst;
+ }
+ }
+
+ free(reply);
+ return num;
+}
+
+EAPI void
+ecore_x_window_prop_xid_list_change(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID item,
+ int op)
+{
+ Ecore_X_ID *lst;
+ int i = 0, num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst);
+ if (num < 0) return;
+
+ for (i = 0; i < num; i++)
+ {
+ if (lst[i] == item) break;
+ }
+
+ if (i < num)
+ {
+ if (op == ECORE_X_PROP_LIST_ADD)
+ goto done;
+ num--;
+ for (; i < num; i++)
+ lst[i] = lst[i + 1];
+ }
+ else
+ {
+ if (op == ECORE_X_PROP_LIST_REMOVE)
+ goto done;
+ num++;
+ lst = realloc(lst, num * sizeof(Ecore_X_ID));
+ lst[i] = item;
+ }
+ ecore_x_window_prop_xid_set(win, atom, type, lst, num);
+
+done:
+ if (lst) free(lst);
+}
+
+EAPI Eina_Bool
+ecore_x_window_prop_protocol_isset(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol)
+{
+ Eina_Bool ret = EINA_FALSE;
+ Ecore_X_Atom proto;
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_t protos;
+#else
+ xcb_icccm_get_wm_protocols_reply_t protos;
+#endif
+ xcb_get_property_cookie_t cookie;
+ uint8_t reply;
+ uint32_t count = 0, i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return EINA_FALSE;
+
+ proto = _ecore_xcb_atoms_wm_protocol[protocol];
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+ reply = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL);
+#else
+ cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+ reply = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie,
+ &protos, NULL);
+#endif
+ if (!reply) return EINA_FALSE;
+
+ count = protos.atoms_len;
+ for (i = 0; i < count; i++)
+ {
+ if (protos.atoms[i] == proto)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&protos);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+#endif
+ return ret;
+}
+
+EAPI Ecore_X_WM_Protocol *
+ecore_x_window_prop_protocol_list_get(Ecore_X_Window win,
+ int *num_ret)
+{
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_t protos;
+#else
+ xcb_icccm_get_wm_protocols_reply_t protos;
+#endif
+ xcb_get_property_cookie_t cookie;
+ uint8_t reply;
+ uint32_t count = 0, i = 0;
+ Ecore_X_WM_Protocol *prot_ret = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!num_ret) return NULL;
+
+ *num_ret = 0;
+
+#ifdef OLD_XCB_VERSION
+ cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+ reply = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL);
+#else
+ cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+ reply = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie,
+ &protos, NULL);
+#endif
+ if (!reply) return NULL;
+
+ count = protos.atoms_len;
+ if (count <= 0)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&protos);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+#endif
+ return NULL;
+ }
+
+ prot_ret = calloc(1, count * sizeof(Ecore_X_WM_Protocol));
+ if (!prot_ret)
+ {
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&protos);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+#endif
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ Ecore_X_WM_Protocol j;
+
+ prot_ret[i] = -1;
+ for (j = 0; j < ECORE_X_WM_PROTOCOL_NUM; j++)
+ {
+ if (_ecore_xcb_atoms_wm_protocol[j] == protos.atoms[i])
+ prot_ret[i] = j;
+ }
+ }
+
+ if (num_ret) *num_ret = count;
+
+#ifdef OLD_XCB_VERSION
+ xcb_get_wm_protocols_reply_wipe(&protos);
+#else
+ xcb_icccm_get_wm_protocols_reply_wipe(&protos);
+#endif
+ return prot_ret;
+}
+
+EAPI Ecore_X_Atom *
+ecore_x_window_prop_list(Ecore_X_Window win,
+ int *num)
+{
+ xcb_list_properties_cookie_t cookie;
+ xcb_list_properties_reply_t *reply;
+ xcb_atom_t *atm;
+ Ecore_X_Atom *atoms;
+ int i = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+
+ cookie = xcb_list_properties_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_list_properties_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+
+ atoms = (Ecore_X_Atom *)malloc(reply->atoms_len * sizeof(Ecore_X_Atom));
+ if (!atoms)
+ {
+ free(reply);
+ return NULL;
+ }
+
+ atm = xcb_list_properties_atoms(reply);
+ for (i = 0; i < reply->atoms_len; i++)
+ atoms[i] = atm[i];
+
+ if (num) *num = reply->atoms_len;
+ free(reply);
+
+ return atoms;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c b/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c
new file mode 100644
index 0000000000..d46e306c8d
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c
@@ -0,0 +1,410 @@
+#include "ecore_xcb_private.h"
+
+typedef struct _Shadow Shadow;
+struct _Shadow
+{
+ Shadow *parent, **children;
+ Ecore_X_Window win;
+ int children_num;
+ short x, y;
+ unsigned short w, h;
+};
+
+static Eina_Bool _inside_rects(Shadow *s,
+ int x,
+ int y,
+ int bx,
+ int by,
+ Ecore_X_Rectangle *rects,
+ int num);
+
+//static int shadow_count = 0;
+static Shadow **shadow_base = NULL;
+static int shadow_num = 0;
+
+/* FIXME: round trips */
+static Shadow *
+_ecore_x_window_tree_walk(Ecore_X_Window window)
+{
+ Shadow *s, **sl;
+ xcb_get_window_attributes_reply_t *reply_attr;
+ xcb_get_geometry_reply_t *reply_geom;
+ xcb_query_tree_reply_t *reply_tree;
+ xcb_get_window_attributes_cookie_t cookie_attr;
+ xcb_get_geometry_cookie_t cookie_geom;
+ xcb_query_tree_cookie_t cookie_tree;
+ int i, j;
+
+ CHECK_XCB_CONN;
+
+ cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window);
+ reply_attr = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_attr, NULL);
+ if (!reply_attr) return NULL;
+ if (reply_attr->map_state != XCB_MAP_STATE_VIEWABLE)
+ {
+ free(reply_attr);
+ return NULL;
+ }
+
+ free(reply_attr);
+
+ cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window);
+ reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL);
+ if (!reply_geom) return NULL;
+
+ if (!(s = calloc(1, sizeof(Shadow))))
+ {
+ free(reply_geom);
+ return NULL;
+ }
+
+ s->win = window;
+ s->x = reply_geom->x;
+ s->y = reply_geom->y;
+ s->w = reply_geom->width;
+ s->h = reply_geom->height;
+
+ free(reply_geom);
+
+ cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, window);
+ reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
+ if (reply_tree)
+ {
+ xcb_window_t *list;
+ int num;
+
+ num = xcb_query_tree_children_length(reply_tree);
+ list = xcb_query_tree_children(reply_tree);
+
+ s->children = calloc(1, sizeof(Shadow *) * num);
+ if (s->children)
+ {
+ s->children_num = num;
+ for (i = 0; i < num; i++)
+ {
+ s->children[i] = _ecore_x_window_tree_walk(list[i]);
+ if (s->children[i])
+ s->children[i]->parent = s;
+ }
+ /* compress list down */
+ j = 0;
+ for (i = 0; i < num; i++)
+ {
+ if (s->children[i])
+ {
+ s->children[j] = s->children[i];
+ j++;
+ }
+ }
+ if (j == 0)
+ {
+ free(s->children);
+ s->children = NULL;
+ s->children_num = 0;
+ }
+ else
+ {
+ s->children_num = j;
+ sl = realloc(s->children, sizeof(Shadow *) * j);
+ if (sl) s->children = sl;
+ }
+ }
+
+ free(reply_tree);
+ }
+
+ return s;
+}
+
+static void
+_ecore_x_window_tree_shadow_free1(Shadow *s)
+{
+ int i = 0;
+
+ if (!s) return;
+ if (s->children)
+ {
+ for (i = 0; i < s->children_num; i++)
+ {
+ if (s->children[i])
+ _ecore_x_window_tree_shadow_free1(s->children[i]);
+ }
+ free(s->children);
+ }
+
+ free(s);
+}
+
+static void
+_ecore_x_window_tree_shadow_free(void)
+{
+ int i = 0;
+
+ if (!shadow_base) return;
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i]) continue;
+ _ecore_x_window_tree_shadow_free1(shadow_base[i]);
+ }
+ free(shadow_base);
+ shadow_base = NULL;
+ shadow_num = 0;
+}
+
+static void
+_ecore_x_window_tree_shadow_populate(void)
+{
+ Ecore_X_Window *roots = NULL;
+ int i = 0, num = 0;
+
+ if ((roots = ecore_x_window_root_list(&num)))
+ {
+ shadow_base = calloc(1, sizeof(Shadow *) * num);
+ if (shadow_base)
+ {
+ shadow_num = num;
+ for (i = 0; i < num; i++)
+ shadow_base[i] = _ecore_x_window_tree_walk(roots[i]);
+ }
+
+ free(roots);
+ }
+}
+
+/*
+ static void
+ _ecore_x_window_tree_shadow_start(void)
+ {
+ shadow_count++;
+ if (shadow_count > 1) return;
+ _ecore_x_window_tree_shadow_populate();
+ }
+
+ static void
+ _ecore_x_window_tree_shadow_stop(void)
+ {
+ shadow_count--;
+ if (shadow_count != 0) return;
+ _ecore_x_window_tree_shadow_free();
+ }
+ */
+
+Shadow *
+_ecore_x_window_shadow_tree_find_shadow(Shadow *s,
+ Ecore_X_Window win)
+{
+ Shadow *ss;
+ int i = 0;
+
+ if (s->win == win) return s;
+
+ if (s->children)
+ {
+ for (i = 0; i < s->children_num; i++)
+ {
+ if (!s->children[i]) continue;
+
+ if ((ss =
+ _ecore_x_window_shadow_tree_find_shadow(s->children[i], win)))
+ return ss;
+ }
+ }
+
+ return NULL;
+}
+
+Shadow *
+_ecore_x_window_shadow_tree_find(Ecore_X_Window base)
+{
+ Shadow *s;
+ int i = 0;
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i]) continue;
+
+ if ((s =
+ _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], base)))
+ return s;
+ }
+ return NULL;
+}
+
+static Ecore_X_Window
+_ecore_x_window_shadow_tree_at_xy_get_shadow(Shadow *s,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Ecore_X_Window child;
+ Ecore_X_Rectangle *rects;
+ int i = 0, j = 0, wx = 0, wy = 0, num = 0;
+
+ wx = s->x + bx;
+ wy = s->y + by;
+ if (!((x >= wx) && (y >= wy) && (x < (wx + s->w)) && (y < (wy + s->h))))
+ return 0;
+
+ rects = ecore_x_window_shape_rectangles_get(s->win, &num);
+ if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
+ num = 0;
+ rects = ecore_x_window_shape_input_rectangles_get(s->win, &num);
+ if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
+
+ if (s->children)
+ {
+ int skipit = 0;
+
+ for (i = s->children_num - 1; i >= 0; --i)
+ {
+ if (!s->children[i]) continue;
+
+ skipit = 0;
+ if (skip)
+ {
+ for (j = 0; j < skip_num; j++)
+ {
+ if (s->children[i]->win == skip[j])
+ {
+ skipit = 1;
+ goto onward;
+ }
+ }
+ }
+onward:
+ if (!skipit)
+ {
+ if ((child =
+ _ecore_x_window_shadow_tree_at_xy_get_shadow(s->children[i], wx, wy, x, y, skip, skip_num)))
+ return child;
+ }
+ }
+ }
+
+ return s->win;
+}
+
+static Ecore_X_Window
+_ecore_x_window_shadow_tree_at_xy_get(Ecore_X_Window base,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Shadow *s;
+
+ if (!shadow_base)
+ {
+ _ecore_x_window_tree_shadow_populate();
+ if (!shadow_base) return 0;
+ }
+
+ s = _ecore_x_window_shadow_tree_find(base);
+ if (!s) return 0;
+
+ return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, bx, by, x, y, skip, skip_num);
+}
+
+static Eina_Bool
+_inside_rects(Shadow *s,
+ int x,
+ int y,
+ int bx,
+ int by,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+ Eina_Bool inside = EINA_FALSE;
+ int i = 0;
+
+ if (!rects) return EINA_FALSE;
+ for (i = 0; i < num; i++)
+ {
+ if ((x >= s->x + bx + rects[i].x) &&
+ (y >= s->y + by + rects[i].y) &&
+ (x < (int)(s->x + bx + rects[i].x + rects[i].width)) &&
+ (y < (int)(s->y + by + rects[i].y + rects[i].height)))
+ {
+ inside = EINA_TRUE;
+ break;
+ }
+ }
+ free(rects);
+ return inside;
+}
+
+/**
+ * Retrieves the top, visible window at the given location,
+ * but skips the windows in the list. This uses a shadow tree built from the
+ * window tree that is only updated the first time
+ * ecore_x_window_shadow_tree_at_xy_with_skip_get() is called, or the next time
+ * it is called after a ecore_x_window_shadow_tree_flush()
+ * @param base The base window to start searching from (normally root).
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @param skip The list of windows to be skipped.
+ * @param skip_num The number of windows to be skipped.
+ * @return The window at the desired position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ return _ecore_x_window_shadow_tree_at_xy_get(base, 0, 0, x, y, skip, skip_num);
+}
+
+/**
+ * Retrieves the parent window a given window has. This uses the shadow window
+ * tree.
+ * @param root The root window of @p win - if 0, this will be automatically determined with extra processing overhead
+ * @param win The window to get the parent window of
+ * @return The parent window of @p win
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_shadow_parent_get(Ecore_X_Window root EINA_UNUSED,
+ Ecore_X_Window win)
+{
+ Shadow *s;
+ int i = 0;
+
+ if (!shadow_base)
+ {
+ _ecore_x_window_tree_shadow_populate();
+ if (!shadow_base) return 0;
+ }
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i]) continue;
+
+ s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win);
+ if (s)
+ {
+ if (!s->parent) return 0;
+ return s->parent->win;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Flushes the window shadow tree so nothing is stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_shadow_tree_flush(void)
+{
+ _ecore_x_window_tree_shadow_free();
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c b/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c
new file mode 100644
index 0000000000..6206a51833
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c
@@ -0,0 +1,790 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_SHAPE
+# include <xcb/shape.h>
+#endif
+
+/**
+ * @defgroup Ecore_X_Window_Shape X Window Shape Functions
+ *
+ * These functions use the shape extension of the X server to change
+ * shape of given windows.
+ */
+
+/**
+ * Sets the input shape of the given window to that given by the pixmap @p mask.
+ * @param win The given window.
+ * @param mask A 1-bit depth pixmap that provides the new input shape of the
+ * window.
+ * @ingroup Ecore_X_Window_Shape
+ */
+EAPI void
+ecore_x_window_shape_input_mask_set(Ecore_X_Window win,
+ Ecore_X_Pixmap mask)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_mask(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT,
+ win, 0, 0, mask);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ mask = 0;
+#endif
+}
+
+/**
+ * Sets the shape of the given window to that given by the pixmap @p mask.
+ * @param win The given window.
+ * @param mask A 2-bit depth pixmap that provides the new shape of the
+ * window.
+ * @ingroup Ecore_X_Window_Shape
+ */
+EAPI void
+ecore_x_window_shape_mask_set(Ecore_X_Window win,
+ Ecore_X_Pixmap mask)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_mask(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING,
+ win, 0, 0, mask);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ mask = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_set(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING,
+ XCB_SHAPE_SK_BOUNDING, win, 0, 0, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_set_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING,
+ XCB_SHAPE_SK_BOUNDING, win, x, y, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+ x = 0;
+ y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangles_set(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t *rect = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!rects) return;
+
+#ifdef ECORE_XCB_SHAPE
+ if (num > 0)
+ {
+ int i = 0;
+
+ if (!(rect = malloc(sizeof(xcb_rectangle_t) * num)))
+ return;
+
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, num, (xcb_rectangle_t *)rect);
+
+ if (rect) free(rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ num = 0;
+ rects = NULL;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_add(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING,
+ win, 0, 0, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_add_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING,
+ win, x, y, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+ x = 0;
+ y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_add(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SUBTRACT,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_clip(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_INTERSECT,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangles_add(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t *rect = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ if (num > 0)
+ {
+ int i = 0;
+
+ if (!(rect = malloc(sizeof(xcb_rectangle_t) * num)))
+ return;
+
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, num, (xcb_rectangle_t *)&rect);
+
+ if (rect) free(rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ num = 0;
+ rects = NULL;
+#endif
+}
+
+EAPI Ecore_X_Rectangle *
+ecore_x_window_shape_rectangles_get(Ecore_X_Window win,
+ int *num_ret)
+{
+ Ecore_X_Rectangle *rects = NULL;
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_get_rectangles_cookie_t cookie;
+ xcb_shape_get_rectangles_reply_t *reply;
+ xcb_rectangle_t *r;
+ unsigned int i = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num_ret) *num_ret = 0;
+
+#ifdef ECORE_XCB_SHAPE
+ cookie =
+ xcb_shape_get_rectangles(_ecore_xcb_conn, win, XCB_SHAPE_SK_BOUNDING);
+ reply = xcb_shape_get_rectangles_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+ if (num_ret) *num_ret = reply->rectangles_len;
+
+ if (reply->rectangles_len < 1)
+ {
+ free(reply);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+
+ rects = malloc(sizeof(Ecore_X_Rectangle) * reply->rectangles_len);
+ if (!rects)
+ {
+ free(reply);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ r = xcb_shape_get_rectangles_rectangles(reply);
+ for (i = 0; i < reply->rectangles_len; i++)
+ {
+ rects[i].x = r[i].x;
+ rects[i].y = r[i].y;
+ rects[i].width = r[i].width;
+ rects[i].height = r[i].height;
+ }
+
+ free(reply);
+
+ return rects;
+#else
+ return rects;
+ win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_events_select(Ecore_X_Window win,
+ Eina_Bool on)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_select_input(_ecore_xcb_conn, win, on);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ on = 0;
+#endif
+}
+
+EAPI Ecore_X_Rectangle *
+ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win,
+ int *num_ret)
+{
+ Ecore_X_Rectangle *rects = NULL;
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_get_rectangles_cookie_t cookie;
+ xcb_shape_get_rectangles_reply_t *reply;
+ xcb_rectangle_t *r;
+ unsigned int i = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num_ret) *num_ret = 0;
+
+#ifdef ECORE_XCB_SHAPE
+ cookie =
+ xcb_shape_get_rectangles(_ecore_xcb_conn, win, XCB_SHAPE_SK_INPUT);
+ reply = xcb_shape_get_rectangles_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+ if (num_ret) *num_ret = reply->rectangles_len;
+
+ if (reply->rectangles_len < 1)
+ {
+ free(reply);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+
+ rects = malloc(sizeof(Ecore_X_Rectangle) * reply->rectangles_len);
+ if (!rects)
+ {
+ free(reply);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ r = xcb_shape_get_rectangles_rectangles(reply);
+ for (i = 0; i < reply->rectangles_len; i++)
+ {
+ rects[i].x = r[i].x;
+ rects[i].y = r[i].y;
+ rects[i].width = r[i].width;
+ rects[i].height = r[i].height;
+ }
+
+ free(reply);
+
+ return rects;
+#else
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+
+ if (!(rects = malloc(sizeof(Ecore_X_Rectangle))))
+ return NULL;
+
+ /* get geometry */
+ cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win);
+ reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ rects[0].x = reply->x;
+ rects[0].y = reply->y;
+ rects[0].width = reply->width;
+ rects[0].height = reply->height;
+ free(reply);
+ }
+ if (num_ret) *num_ret = 1;
+ return rects;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t *rect = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!rects) return;
+
+#ifdef ECORE_XCB_SHAPE
+ if (num > 0)
+ {
+ int i = 0;
+
+ if (!(rect = malloc(sizeof(xcb_rectangle_t) * num)))
+ return;
+
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, num, (xcb_rectangle_t *)rect);
+
+ if (rect) free(rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ num = 0;
+ rects = NULL;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SUBTRACT,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT,
+ XCB_SHAPE_SK_INPUT, win, x, y, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+ x = 0;
+ y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_INPUT,
+ XCB_SHAPE_SK_INPUT, win, x, y, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+ x = 0;
+ y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_window_set(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT,
+ XCB_SHAPE_SK_INPUT, win, 0, 0, shape_win);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ shape_win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t rect;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_INTERSECT,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, 1, &rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XCB_SHAPE
+ xcb_rectangle_t *rect = NULL;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+#ifdef ECORE_XCB_SHAPE
+ if (num > 0)
+ {
+ int i = 0;
+
+ if (!(rect = malloc(sizeof(xcb_rectangle_t) * num)))
+ return;
+
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+
+ xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION,
+ XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
+ win, 0, 0, num, (xcb_rectangle_t *)&rect);
+
+ if (rect) free(rect);
+// ecore_x_flush();
+#else
+ return;
+ win = 0;
+ num = 0;
+ rects = NULL;
+#endif
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c b/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c
new file mode 100644
index 0000000000..e0e56102e2
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c
@@ -0,0 +1,116 @@
+#include "ecore_xcb_private.h"
+#include <fnmatch.h>
+
+/* local function prototypes */
+static Eina_Bool _ecore_xcb_xdefaults_glob_match(const char *str,
+ const char *glob);
+
+/* local variables */
+static Eina_File *_ecore_xcb_xdefaults_file = NULL;
+static char *_ecore_xcb_xdefaults_data = NULL;
+
+void
+_ecore_xcb_xdefaults_init(void)
+{
+ char buff[PATH_MAX];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ snprintf(buff, sizeof(buff), "%s/.Xdefaults", getenv("HOME"));
+ if ((_ecore_xcb_xdefaults_file = eina_file_open(buff, EINA_FALSE)))
+ {
+ eina_mmap_safety_enabled_set(EINA_TRUE);
+
+ _ecore_xcb_xdefaults_data =
+ eina_file_map_all(_ecore_xcb_xdefaults_file, EINA_FILE_SEQUENTIAL);
+ }
+}
+
+void
+_ecore_xcb_xdefaults_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!_ecore_xcb_xdefaults_file) return;
+ if (_ecore_xcb_xdefaults_data)
+ eina_file_map_free(_ecore_xcb_xdefaults_file, _ecore_xcb_xdefaults_data);
+ if (_ecore_xcb_xdefaults_file) eina_file_close(_ecore_xcb_xdefaults_file);
+}
+
+char *
+_ecore_xcb_xdefaults_string_get(const char *prog,
+ const char *param)
+{
+ char buff[1024], ret[1024];
+ char *str = NULL;
+ char **ea = NULL;
+ unsigned int count = 0, i = 0;
+
+ if ((!_ecore_xcb_xdefaults_data) || (!_ecore_xcb_xdefaults_file))
+ return NULL;
+
+ snprintf(buff, sizeof(buff), "*%s*.*%s*", prog, param);
+
+ str = _ecore_xcb_xdefaults_data;
+ ea = eina_str_split_full(str, "\n", -1, &count);
+ for (i = 0; i < count; i++)
+ {
+ if (_ecore_xcb_xdefaults_glob_match(ea[i], buff))
+ sscanf(ea[i], "%*[^:]:%*[ ]%s", ret);
+ }
+ if ((ea) && (ea[0]))
+ {
+ free(ea[0]);
+ free(ea);
+ }
+
+ return strdup(ret);
+}
+
+int
+_ecore_xcb_xdefaults_int_get(const char *prog,
+ const char *param)
+{
+ char buff[1024];
+ char *str = NULL;
+ char **ea = NULL;
+ unsigned int count = 0, i = 0;
+ int ret = -1;
+
+ if ((!_ecore_xcb_xdefaults_data) || (!_ecore_xcb_xdefaults_file))
+ return 0;
+
+ snprintf(buff, sizeof(buff), "*%s*.*%s*", prog, param);
+
+ str = _ecore_xcb_xdefaults_data;
+ ea = eina_str_split_full(str, "\n", -1, &count);
+ for (i = 0; i < count; i++)
+ {
+ if (_ecore_xcb_xdefaults_glob_match(ea[i], buff))
+ sscanf(ea[i], "%*[^:]:%*[ ]%d", &ret);
+ }
+ if ((ea) && (ea[0]))
+ {
+ free(ea[0]);
+ free(ea);
+ }
+
+ return ret;
+}
+
+/* local functions */
+static Eina_Bool
+_ecore_xcb_xdefaults_glob_match(const char *str,
+ const char *glob)
+{
+ if ((!str) || (!glob)) return EINA_FALSE;
+ if (glob[0] == 0)
+ {
+ if (str[0] == 0) return EINA_TRUE;
+ return EINA_FALSE;
+ }
+ if (!strcmp(glob, "*")) return EINA_TRUE;
+ if (!fnmatch(glob, str, 0)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c b/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c
new file mode 100644
index 0000000000..58444cdf1f
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c
@@ -0,0 +1,744 @@
+#include "ecore_xcb_private.h"
+# ifdef ECORE_XCB_XFIXES
+# include <xcb/xfixes.h>
+# endif
+
+/* local function prototypes */
+static xcb_rectangle_t *_ecore_xcb_rect_to_xcb(Ecore_X_Rectangle *rects,
+ int num);
+static Ecore_X_Rectangle *_ecore_xcb_rect_to_ecore(xcb_rectangle_t *rects,
+ int num);
+
+/* local variables */
+static Eina_Bool _xfixes_avail = EINA_FALSE;
+
+/* external variables */
+int _ecore_xcb_event_xfixes = -1;
+
+void
+_ecore_xcb_xfixes_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xfixes_id);
+#endif
+}
+
+void
+_ecore_xcb_xfixes_finalize(void)
+{
+#ifdef ECORE_XCB_XFIXES
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XFIXES
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xfixes_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_xfixes_query_version_cookie_t cookie;
+ xcb_xfixes_query_version_reply_t *reply;
+
+ cookie =
+ xcb_xfixes_query_version_unchecked(_ecore_xcb_conn,
+ XCB_XFIXES_MAJOR_VERSION,
+ XCB_XFIXES_MINOR_VERSION);
+ reply = xcb_xfixes_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ /* NB: XFixes Extension >= 3 needed for shape stuff.
+ * for now, I am removing this check so that it matches the
+ * xlib code closer. If the extension version ends up being
+ * that important, then re-enable this */
+
+ /* if (reply->major_version >= 3) */
+ _xfixes_avail = EINA_TRUE;
+ free(reply);
+ }
+
+ if (_xfixes_avail)
+ _ecore_xcb_event_xfixes = ext_reply->first_event;
+ }
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection)
+{
+#ifdef ECORE_XCB_XFIXES
+ Ecore_X_Window root = 0;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+ int mask = 0;
+#endif
+
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_XFIXES
+ root = ((xcb_screen_t *)_ecore_xcb_screen)->root;
+
+ mask = (XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
+ XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
+
+ cookie =
+ xcb_xfixes_select_selection_input_checked(_ecore_xcb_conn, root,
+ selection, mask);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#endif
+ return EINA_FALSE;
+}
+
+Eina_Bool
+_ecore_xcb_xfixes_avail_get(void)
+{
+ return _xfixes_avail;
+}
+
+/**
+ * @defgroup Ecore_X_Fixes_Group X Fixes Extension Functions
+ *
+ * Functions related to the X Fixes extension.
+ */
+
+/**
+ * Create a region from rectangles.
+ * @param rects The rectangles used to initialize the region.
+ * @param num The number of rectangles.
+ * @return The newly created region.
+ *
+ * Create a region initialized to the specified list of rectangles
+ * @p rects. The rectangles may be specified in any order, their union
+ * becomes the region.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Region
+ecore_x_region_new(Ecore_X_Rectangle *rects,
+ int num)
+{
+ Ecore_X_Region region = 0;
+#ifdef ECORE_XCB_XFIXES
+ xcb_rectangle_t *xrects;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return 0;
+
+#ifdef ECORE_XCB_XFIXES
+ xrects = _ecore_xcb_rect_to_xcb(rects, num);
+ region = xcb_generate_id(_ecore_xcb_conn);
+ xcb_xfixes_create_region(_ecore_xcb_conn, region, num, xrects);
+ free(xrects);
+// ecore_x_flush();
+#endif
+
+ return region;
+}
+
+/**
+ * Create a region from a pixmap.
+ * @param bitmap The bitmap used to initialize the region.
+ * @return The newly created region.
+ *
+ * Creates a region initialized to the set of 'one' pixels in @p bitmap
+ * (which must be of depth 1, else Match error).
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Region
+ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap)
+{
+ Ecore_X_Region region = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return 0;
+
+#ifdef ECORE_XCB_XFIXES
+ region = xcb_generate_id(_ecore_xcb_conn);
+ xcb_xfixes_create_region_from_bitmap(_ecore_xcb_conn, region, bitmap);
+// ecore_x_flush();
+#endif
+
+ return region;
+}
+
+/**
+ * Create a region from a window.
+ * @param win The window used to initialize the region.
+ * @param type The type of the region.
+ * @return The newly created region.
+ *
+ * Creates a region initialized to the specified @p window region. See
+ * the Shape extension for the definition of Bounding and Clip
+ * regions.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Region
+ecore_x_region_new_from_window(Ecore_X_Window win,
+ Ecore_X_Region_Type type)
+{
+ Ecore_X_Region region = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return 0;
+
+#ifdef ECORE_XCB_XFIXES
+ region = xcb_generate_id(_ecore_xcb_conn);
+ xcb_xfixes_create_region_from_window(_ecore_xcb_conn, region, win, type);
+// ecore_x_flush();
+#endif
+
+ return region;
+}
+
+/**
+ * Create a region from a graphic context.
+ * @param gc The graphic context used to initialize the region.
+ * @return The newly created region.
+ *
+ * Creates a region initialized from the clip list of @p gc.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Region
+ecore_x_region_new_from_gc(Ecore_X_GC gc)
+{
+ Ecore_X_Region region = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return 0;
+
+#ifdef ECORE_XCB_XFIXES
+ region = xcb_generate_id(_ecore_xcb_conn);
+ xcb_xfixes_create_region_from_gc(_ecore_xcb_conn, region, gc);
+// ecore_x_flush();
+#endif
+
+ return region;
+}
+
+/**
+ * Create a region from a picture.
+ * @param picture The picture used to initialize the region.
+ * @return The newly created region.
+ *
+ * Creates a region initialized from the clip list of @p picture.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Region
+ecore_x_region_new_from_picture(Ecore_X_Picture picture)
+{
+ Ecore_X_Region region = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return 0;
+
+#ifdef ECORE_XCB_XFIXES
+ region = xcb_generate_id(_ecore_xcb_conn);
+ xcb_xfixes_create_region_from_picture(_ecore_xcb_conn, region, picture);
+// ecore_x_flush();
+#endif
+
+ return region;
+}
+
+/**
+ * Destroy a region.
+ * @param region The region to destroy.
+ *
+ * Destroy the specified @p region.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_free(Ecore_X_Region region)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_destroy_region(_ecore_xcb_conn, region);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Set the content of a region.
+ * @param region The region to destroy.
+ * @param rects The rectangles used to set the region.
+ * @param num The number of rectangles.
+ *
+ * Replace the current contents of @p region with the region formed
+ * by the union of the rectangles @p rects.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_set(Ecore_X_Region region,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XCB_XFIXES
+ xcb_rectangle_t *xrects;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xrects = _ecore_xcb_rect_to_xcb(rects, num);
+ xcb_xfixes_set_region(_ecore_xcb_conn, region, num, xrects);
+ free(xrects);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Copy the content of a region.
+ * @param dest The destination region.
+ * @param source The source region.
+ *
+ * Replace the contents of @p dest with the contents of @p source.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_copy(Ecore_X_Region dest,
+ Ecore_X_Region source)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+ // NB: Hmmmm...this may need converting to/fro xcb_rectangle_t
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_copy_region(_ecore_xcb_conn, source, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Make the union of two regions.
+ * @param dest The destination region.
+ * @param source1 The first source region.
+ * @param source2 The second source region.
+ *
+ * Replace the contents of @p dest with the union of @p source1 and
+ * @p source2.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_combine(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_union_region(_ecore_xcb_conn, source1, source2, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Make the intersection of two regions.
+ * @param dest The destination region.
+ * @param source1 The first source region.
+ * @param source2 The second source region.
+ *
+ * Replace the contents of @p dest with the intersection of @p source1 and
+ * @p source2.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_intersect(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_intersect_region(_ecore_xcb_conn, source1, source2, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Make the subtraction of two regions.
+ * @param dest The destination region.
+ * @param source1 The first source region.
+ * @param source2 The second source region.
+ *
+ * Replace the contents of @p dest with the subtraction of @p source1 by
+ * @p source2.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_subtract(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_subtract_region(_ecore_xcb_conn, source1, source2, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Make the subtraction of regions by bounds.
+ * @param dest The destination region.
+ * @param bounds The bounds.
+ * @param source The source region.
+ *
+ * The @p source region is subtracted from the region specified by
+ * @p bounds. The result is placed in @p dest, replacing its
+ * contents.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_invert(Ecore_X_Region dest,
+ Ecore_X_Rectangle *bounds,
+ Ecore_X_Region source)
+{
+#ifdef ECORE_XCB_XFIXES
+ xcb_rectangle_t xrects;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xrects.x = bounds->x;
+ xrects.y = bounds->y;
+ xrects.width = bounds->width;
+ xrects.height = bounds->height;
+
+ xcb_xfixes_invert_region(_ecore_xcb_conn, source, xrects, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Translate a region.
+ * @param region The region to translate.
+ * @param dx The horizontal translation.
+ * @param dy The vertical translation.
+ *
+ * The @p region is translated by @p dx and @p dy in place.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_translate(Ecore_X_Region region,
+ int dx,
+ int dy)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_translate_region(_ecore_xcb_conn, region, dx, dy);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Extent a region.
+ * @param dest The destination region.
+ * @param source The source region.
+ *
+ * The extents of the @p source region are placed in @p dest.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_extents(Ecore_X_Region dest,
+ Ecore_X_Region source)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_region_extents(_ecore_xcb_conn, source, dest);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Return the rectangles that compose a region.
+ * @param region The region (Unused).
+ * @param num The number of returned rectangles.
+ * @param bounds The returned bounds of the region.
+ * @return The returned rectangles.
+ *
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI Ecore_X_Rectangle *
+ecore_x_region_fetch(Ecore_X_Region region,
+ int *num,
+ Ecore_X_Rectangle *bounds)
+{
+ Ecore_X_Rectangle extents = { 0, 0, 0, 0 };
+ Ecore_X_Rectangle *rects = NULL;
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_fetch_region_cookie_t cookie;
+ xcb_xfixes_fetch_region_reply_t *reply;
+ xcb_rectangle_t *r;
+ int n = 0;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (num) *num = 0;
+ if (bounds) *bounds = extents;
+ if (!_xfixes_avail) return NULL;
+
+#ifdef ECORE_XCB_XFIXES
+ cookie = xcb_xfixes_fetch_region_unchecked(_ecore_xcb_conn, region);
+ reply = xcb_xfixes_fetch_region_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return NULL;
+
+ r = xcb_xfixes_fetch_region_rectangles(reply);
+ n = xcb_xfixes_fetch_region_rectangles_length(reply);
+ rects = _ecore_xcb_rect_to_ecore(r, n);
+ if (num) *num = n;
+
+ /* rects = (Ecore_X_Rectangle *)malloc(n * sizeof(Ecore_X_Rectangle)); */
+ /* if (!rects) */
+ /* { */
+ /* free(reply); */
+ /* return NULL; */
+ /* } */
+
+ /* for (i = 0; i < n; i++) */
+ /* { */
+ /* rects[i].x = r[i].x; */
+ /* rects[i].y = r[i].y; */
+ /* rects[i].width = r[i].width; */
+ /* rects[i].height = r[i].height; */
+ /* } */
+
+ (*bounds).x = reply->extents.x;
+ (*bounds).y = reply->extents.y;
+ (*bounds).width = reply->extents.width;
+ (*bounds).height = reply->extents.height;
+
+ free(reply);
+#endif
+
+ return rects;
+}
+
+/**
+ * Expand a region.
+ * @param dest The destination region.
+ * @param source The source region.
+ * @param left The number of pixels to add on the left.
+ * @param right The number of pixels to add on the right.
+ * @param top The number of pixels to add at the top.
+ * @param bottom The number of pixels to add at the bottom.
+ *
+ * Put in @p dest the area specified by expanding each rectangle in
+ * the @p source region by the specified number of pixels to the
+ * @p left, @p right, @p top and @p bottom.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_expand(Ecore_X_Region dest,
+ Ecore_X_Region source,
+ unsigned int left,
+ unsigned int right,
+ unsigned int top,
+ unsigned int bottom)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_expand_region(_ecore_xcb_conn, source, dest, left, right, top, bottom);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Change clip-mask in a graphic context to the specified region.
+ * @param region The region to change.
+ * @param gc The clip-mask graphic context.
+ * @param x The horizontal translation.
+ * @param y The vertical translation.
+ *
+ * Changes clip-mask in @p gc to the specified @p region and
+ * sets the clip origin with the values of @p x_origin and @p y_origin.
+ * Output will be clippped to remain contained within the region. The
+ * clip origin is interpreted relative to the origin of whatever
+ * destination drawable is specified in a graphics request. The
+ * region is interpreted relative to the clip origin. Future changes
+ * to region have no effect on the gc clip-mask.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_gc_clip_set(Ecore_X_Region region,
+ Ecore_X_GC gc,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_set_gc_clip_region(_ecore_xcb_conn, gc, region, x, y);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Change the shape extension of a window.
+ * @param region The region.
+ * @param dest The window whose shape is changed.
+ * @param type The kind of shape.
+ * @param x The horizontal offset.
+ * @param y The vertical offset.
+ *
+ * Set the specified Shape extension region of @p window to @p region,
+ * offset by @p x_offset and @p y_offset. Future changes to region
+ * have no effect on the window shape.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_window_shape_set(Ecore_X_Region region,
+ Ecore_X_Window dest,
+ Ecore_X_Shape_Type type,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_set_window_shape_region(_ecore_xcb_conn, dest, type, x, y, region);
+// ecore_x_flush();
+#endif
+}
+
+/**
+ * Change clip-mask in picture to the specified region.
+ * @param region The region.
+ * @param picture The picture.
+ * @param x The X coordinate of the origin.
+ * @param y The Y coordinate of the origin.
+ *
+ * Changes clip-mask in picture to the specified @p region
+ * and sets the clip origin. Input and output will be clipped to
+ * remain contained within the region. The clip origin is interpreted
+ * relative to the origin of the drawable associated with @p picture. The
+ * region is interpreted relative to the clip origin. Future changes
+ * to region have no effect on the picture clip-mask.
+ * @ingroup Ecore_X_Fixes_Group
+ */
+EAPI void
+ecore_x_region_picture_clip_set(Ecore_X_Region region,
+ Ecore_X_Picture picture,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xfixes_avail) return;
+
+#ifdef ECORE_XCB_XFIXES
+ xcb_xfixes_set_picture_clip_region(_ecore_xcb_conn, picture, region, x, y);
+// ecore_x_flush();
+#endif
+}
+
+/* local function prototypes */
+static xcb_rectangle_t *
+_ecore_xcb_rect_to_xcb(Ecore_X_Rectangle *rects,
+ int num)
+{
+ xcb_rectangle_t *xrect;
+ int i = 0;
+
+ if (!num) return NULL;
+
+ xrect = malloc(sizeof(xcb_rectangle_t) * num);
+ if (!xrect) return NULL;
+
+ for (i = 0; i < num; i++)
+ {
+ xrect[i].x = rects[i].x;
+ xrect[i].y = rects[i].y;
+ xrect[i].width = rects[i].width;
+ xrect[i].height = rects[i].height;
+ }
+
+ return xrect;
+}
+
+static Ecore_X_Rectangle *
+_ecore_xcb_rect_to_ecore(xcb_rectangle_t *rects,
+ int num)
+{
+ Ecore_X_Rectangle *erect;
+ int i = 0;
+
+ if (!num) return NULL;
+
+ erect = malloc(sizeof(Ecore_X_Rectangle) * num);
+ if (!erect) return NULL;
+
+ for (i = 0; i < num; i++)
+ {
+ erect[i].x = rects[i].x;
+ erect[i].y = rects[i].y;
+ erect[i].width = rects[i].width;
+ erect[i].height = rects[i].height;
+ }
+
+ return erect;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c b/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c
new file mode 100644
index 0000000000..37a2339e9b
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c
@@ -0,0 +1,139 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_XINERAMA
+# include <xcb/xinerama.h>
+#endif
+
+/* local variables */
+static Eina_Bool _xinerama_avail = EINA_FALSE;
+static Eina_Bool _xinerama_active = EINA_FALSE;
+
+void
+_ecore_xcb_xinerama_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XINERAMA
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xinerama_id);
+#endif
+}
+
+void
+_ecore_xcb_xinerama_finalize(void)
+{
+#ifdef ECORE_XCB_XINERAMA
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XINERAMA
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xinerama_id);
+ if ((ext_reply) && (ext_reply->present))
+ {
+ xcb_xinerama_query_version_cookie_t cookie;
+ xcb_xinerama_query_version_reply_t *reply;
+
+ cookie =
+ xcb_xinerama_query_version_unchecked(_ecore_xcb_conn,
+ XCB_XINERAMA_MAJOR_VERSION,
+ XCB_XINERAMA_MINOR_VERSION);
+ reply =
+ xcb_xinerama_query_version_reply(_ecore_xcb_conn, cookie, NULL);
+ if (reply)
+ {
+ _xinerama_avail = EINA_TRUE;
+ // NB: Do we need to compare version numbers here ?
+ free(reply);
+ }
+
+ if (_xinerama_avail)
+ {
+ xcb_xinerama_is_active_cookie_t acookie;
+ xcb_xinerama_is_active_reply_t *areply;
+
+ acookie = xcb_xinerama_is_active_unchecked(_ecore_xcb_conn);
+ areply =
+ xcb_xinerama_is_active_reply(_ecore_xcb_conn, acookie, NULL);
+ if (areply)
+ {
+ _xinerama_active = areply->state;
+ free(areply);
+ }
+ }
+ }
+#endif
+}
+
+EAPI int
+ecore_x_xinerama_screen_count_get(void)
+{
+ int count = 0;
+#ifdef ECORE_XCB_XINERAMA
+ xcb_xinerama_query_screens_cookie_t cookie;
+ xcb_xinerama_query_screens_reply_t *reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_xinerama_avail) return 0;
+
+#ifdef ECORE_XCB_XINERAMA
+ cookie = xcb_xinerama_query_screens_unchecked(_ecore_xcb_conn);
+ reply =
+ xcb_xinerama_query_screens_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return 0;
+ count = reply->number;
+#endif
+
+ return count;
+}
+
+EAPI Eina_Bool
+ecore_x_xinerama_screen_geometry_get(int screen,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+#ifdef ECORE_XCB_XINERAMA
+ xcb_xinerama_query_screens_cookie_t cookie;
+ xcb_xinerama_query_screens_reply_t *reply;
+ xcb_xinerama_screen_info_t *info;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (w) *w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels;
+ if (h) *h = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels;
+
+ if (!_xinerama_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_XINERAMA
+ cookie = xcb_xinerama_query_screens_unchecked(_ecore_xcb_conn);
+ reply =
+ xcb_xinerama_query_screens_reply(_ecore_xcb_conn, cookie, NULL);
+ if (!reply) return EINA_FALSE;
+
+ info = xcb_xinerama_query_screens_screen_info(reply);
+ if (!info)
+ {
+ free(reply);
+ return EINA_FALSE;
+ }
+
+ if (x) *x = info[screen].x_org;
+ if (y) *y = info[screen].y_org;
+ if (w) *w = info[screen].width;
+ if (h) *h = info[screen].height;
+
+ free(reply);
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xtest.c b/src/lib/ecore_x/xcb/ecore_xcb_xtest.c
new file mode 100644
index 0000000000..7f76b2ccb5
--- /dev/null
+++ b/src/lib/ecore_x/xcb/ecore_xcb_xtest.c
@@ -0,0 +1,215 @@
+#include "ecore_xcb_private.h"
+#ifdef ECORE_XCB_XTEST
+# include <xcb/xtest.h>
+# include <X11/keysym.h>
+#endif
+
+/* local variables */
+static Eina_Bool _test_avail = EINA_FALSE;
+
+void
+_ecore_xcb_xtest_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XTEST
+ xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_test_id);
+#endif
+}
+
+void
+_ecore_xcb_xtest_finalize(void)
+{
+#ifdef ECORE_XCB_XTEST
+ const xcb_query_extension_reply_t *ext_reply;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+#ifdef ECORE_XCB_XTEST
+ ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_test_id);
+ if ((ext_reply) && (ext_reply->present))
+ _test_avail = EINA_TRUE;
+#endif
+}
+
+EAPI Eina_Bool
+#ifdef ECORE_XCB_XTEST
+ecore_x_test_fake_key_down(const char *key)
+#else
+ecore_x_test_fake_key_down(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XTEST
+ xcb_keycode_t keycode = 0;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_test_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_XTEST
+ keycode = _ecore_xcb_keymap_string_to_keycode(key);
+ if (keycode == XCB_NO_SYMBOL) return EINA_FALSE;
+
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS,
+ keycode, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+#ifdef ECORE_XCB_XTEST
+ecore_x_test_fake_key_up(const char *key)
+#else
+ecore_x_test_fake_key_up(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XTEST
+ xcb_keycode_t keycode = 0;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_test_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_XTEST
+ keycode = _ecore_xcb_keymap_string_to_keycode(key);
+ if (keycode == XCB_NO_SYMBOL) return EINA_FALSE;
+
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE,
+ keycode, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+#ifdef ECORE_XCB_XTEST
+ecore_x_test_fake_key_press(const char *key)
+#else
+ecore_x_test_fake_key_press(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XCB_XTEST
+ xcb_keycode_t keycode = 0;
+ xcb_keysym_t keysym = 0;
+ xcb_keycode_t shift_code = 0;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *err;
+ Eina_Bool shift = EINA_FALSE;
+#endif
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ CHECK_XCB_CONN;
+
+ if (!_test_avail) return EINA_FALSE;
+
+#ifdef ECORE_XCB_XTEST
+ keycode = _ecore_xcb_keymap_string_to_keycode(key);
+ keysym = _ecore_xcb_keymap_keycode_to_keysym(keycode, 0);
+ if (keysym == XCB_NO_SYMBOL)
+ {
+ keysym = _ecore_xcb_keymap_keycode_to_keysym(keycode, 1);
+ if (keysym != XCB_NO_SYMBOL)
+ shift = EINA_TRUE;
+ }
+
+ if (shift)
+ {
+ xcb_keycode_t *keycodes;
+ int i = 0;
+
+ keycodes = _ecore_xcb_keymap_keysym_to_keycode(XK_Shift_L);
+ while (keycodes[i] != XCB_NO_SYMBOL)
+ {
+ if (keycodes[i] != 0)
+ {
+ shift_code = keycodes[i];
+ break;
+ }
+ i++;
+ }
+ }
+
+ if (shift)
+ {
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS,
+ shift_code, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+ }
+
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS,
+ keycode, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE,
+ keycode, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+
+ if (shift)
+ {
+ cookie =
+ xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE,
+ shift_code, XCB_CURRENT_TIME,
+ ((xcb_screen_t *)_ecore_xcb_screen)->root,
+ 0, 0, 0);
+ err = xcb_request_check(_ecore_xcb_conn, cookie);
+ if (err)
+ {
+ free(err);
+ return EINA_FALSE;
+ }
+ }
+
+ return EINA_TRUE;
+#endif
+
+ return EINA_FALSE;
+}
diff --git a/src/lib/ecore_x/xlib/ecore_x.c b/src/lib/ecore_x/xlib/ecore_x.c
new file mode 100644
index 0000000000..d9b81bc0f8
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x.c
@@ -0,0 +1,2242 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+//#define LOGRT 1
+
+#ifdef LOGRT
+#include <dlfcn.h>
+#endif /* ifdef LOGRT */
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+#include "Ecore_Input.h"
+
+static Eina_Bool _ecore_x_fd_handler(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static Eina_Bool _ecore_x_fd_handler_buf(void *data,
+ Ecore_Fd_Handler *fd_handler);
+static int _ecore_x_key_mask_get(KeySym sym);
+static int _ecore_x_event_modifier(unsigned int state);
+
+static Ecore_Fd_Handler *_ecore_x_fd_handler_handle = NULL;
+
+static const int AnyXEvent = 0; /* 0 can be used as there are no event types
+ * with index 0 and 1 as they are used for
+ * errors
+ */
+
+static int _ecore_x_event_shape_id = 0;
+static int _ecore_x_event_screensaver_id = 0;
+static int _ecore_x_event_sync_id = 0;
+int _ecore_xlib_log_dom = -1;
+
+#ifdef ECORE_XRANDR
+static int _ecore_x_event_randr_id = 0;
+#endif /* ifdef ECORE_XRANDR */
+#ifdef ECORE_XFIXES
+static int _ecore_x_event_fixes_selection_id = 0;
+#endif /* ifdef ECORE_XFIXES */
+#ifdef ECORE_XDAMAGE
+static int _ecore_x_event_damage_id = 0;
+#endif /* ifdef ECORE_XDAMAGE */
+#ifdef ECORE_XGESTURE
+static int _ecore_x_event_gesture_id = 0;
+#endif /* ifdef ECORE_XGESTURE */
+#ifdef ECORE_XKB
+static int _ecore_x_event_xkb_id = 0;
+#endif /* ifdef ECORE_XKB */
+static int _ecore_x_event_handlers_num = 0;
+static void (**_ecore_x_event_handlers) (XEvent * event) = NULL;
+
+static int _ecore_x_init_count = 0;
+static int _ecore_x_grab_count = 0;
+
+Display *_ecore_x_disp = NULL;
+double _ecore_x_double_click_time = 0.25;
+Time _ecore_x_event_last_time = 0;
+Window _ecore_x_event_last_win = 0;
+int _ecore_x_event_last_root_x = 0;
+int _ecore_x_event_last_root_y = 0;
+Eina_Bool _ecore_x_xcursor = EINA_FALSE;
+
+Ecore_X_Window _ecore_x_private_win = 0;
+
+Ecore_X_Atom _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM];
+
+EAPI int ECORE_X_EVENT_ANY = 0;
+EAPI int ECORE_X_EVENT_MOUSE_IN = 0;
+EAPI int ECORE_X_EVENT_MOUSE_OUT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_FOCUS_IN = 0;
+EAPI int ECORE_X_EVENT_WINDOW_FOCUS_OUT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_KEYMAP = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DAMAGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CREATE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DESTROY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_HIDE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHOW = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHOW_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_REPARENT = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_GRAVITY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STACK = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STACK_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_PROPERTY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_COLORMAP = 0;
+EAPI int ECORE_X_EVENT_WINDOW_MAPPING = 0;
+EAPI int ECORE_X_EVENT_MAPPING_CHANGE = 0;
+EAPI int ECORE_X_EVENT_SELECTION_CLEAR = 0;
+EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0;
+EAPI int ECORE_X_EVENT_SELECTION_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_CLIENT_MESSAGE = 0;
+EAPI int ECORE_X_EVENT_WINDOW_SHAPE = 0;
+EAPI int ECORE_X_EVENT_SCREENSAVER_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PAN;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAP;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD;
+EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP;
+EAPI int ECORE_X_EVENT_SYNC_COUNTER = 0;
+EAPI int ECORE_X_EVENT_SYNC_ALARM = 0;
+EAPI int ECORE_X_EVENT_SCREEN_CHANGE = 0;
+EAPI int ECORE_X_EVENT_DAMAGE_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_RANDR_CRTC_CHANGE = 0;
+EAPI int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = 0;
+EAPI int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_WINDOW_DELETE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_WINDOW_STATE_REQUEST = 0;
+EAPI int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = 0;
+EAPI int ECORE_X_EVENT_PING = 0;
+EAPI int ECORE_X_EVENT_DESKTOP_CHANGE = 0;
+
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = 0;
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = 0;
+EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = 0;
+
+EAPI int ECORE_X_EVENT_XKB_STATE_NOTIFY = 0;
+EAPI int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = 0;
+
+
+EAPI int ECORE_X_EVENT_GENERIC = 0;
+
+EAPI int ECORE_X_MODIFIER_SHIFT = 0;
+EAPI int ECORE_X_MODIFIER_CTRL = 0;
+EAPI int ECORE_X_MODIFIER_ALT = 0;
+EAPI int ECORE_X_MODIFIER_WIN = 0;
+EAPI int ECORE_X_MODIFIER_ALTGR = 0;
+
+EAPI int ECORE_X_LOCK_SCROLL = 0;
+EAPI int ECORE_X_LOCK_NUM = 0;
+EAPI int ECORE_X_LOCK_CAPS = 0;
+EAPI int ECORE_X_LOCK_SHIFT = 0;
+
+EAPI int ECORE_X_RAW_BUTTON_PRESS = 0;
+EAPI int ECORE_X_RAW_BUTTON_RELEASE = 0;
+EAPI int ECORE_X_RAW_MOTION = 0;
+
+#ifdef LOGRT
+static double t0 = 0.0;
+static Status (*_logrt_real_reply)(Display *disp,
+ void *rep,
+ int extra,
+ Bool discard) = NULL;
+static void
+_logrt_init(void)
+{
+ void *lib;
+
+ lib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY);
+ if (!lib)
+ lib = dlopen("libX11.so.6", RTLD_GLOBAL | RTLD_LAZY);
+
+ if (!lib)
+ lib = dlopen("libX11.so.6.3", RTLD_GLOBAL | RTLD_LAZY);
+
+ if (!lib)
+ lib = dlopen("libX11.so.6.3.0", RTLD_GLOBAL | RTLD_LAZY);
+
+ _logrt_real_reply = dlsym(lib, "_XReply");
+ t0 = ecore_time_get();
+}
+
+Status
+_XReply(Display *disp,
+ void *rep,
+ int extra,
+ Bool discard)
+{
+ void *bt[128];
+ int i, n;
+ char **sym;
+
+ n = backtrace(bt, 128);
+ if (n > 0)
+ {
+ sym = backtrace_symbols(bt, n);
+ printf("ROUNDTRIP: %4.4f :", ecore_time_get() - t0);
+ if (sym)
+ {
+ for (i = n - 1; i > 0; i--)
+ {
+ char *fname = strchr(sym[i], '(');
+ if (fname)
+ {
+ char *tsym = alloca(strlen(fname) + 1);
+ char *end;
+ strcpy(tsym, fname + 1);
+ end = strchr(tsym, '+');
+ if (end)
+ {
+ *end = 0;
+ printf("%s", tsym);
+ }
+ else
+ printf("???");
+ }
+ else
+ printf("???");
+
+ if (i > 1)
+ printf(" > ");
+ }
+ printf("\n");
+ }
+ }
+
+ // fixme: logme
+ return _logrt_real_reply(disp, rep, extra, discard);
+}
+
+#endif /* ifdef LOGRT */
+
+/* wrapper to use XkbKeycodeToKeysym when possible */
+KeySym
+_ecore_x_XKeycodeToKeysym(Display *display, KeyCode keycode, int idx)
+{
+#ifdef ECORE_XKB
+ return XkbKeycodeToKeysym(display, keycode, 0, idx);
+#else
+ return XKeycodeToKeysym(display, keycode, idx);
+#endif
+}
+
+void
+_ecore_x_modifiers_get(void)
+{
+ /* everything has these... unless its like a pda... :) */
+ ECORE_X_MODIFIER_SHIFT = _ecore_x_key_mask_get(XK_Shift_L);
+ ECORE_X_MODIFIER_CTRL = _ecore_x_key_mask_get(XK_Control_L);
+
+ /* apple's xdarwin has no alt!!!! */
+ ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Alt_L);
+ if (!ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Meta_L);
+
+ if (!ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Super_L);
+
+ /* the windows key... a valid modifier :) */
+ ECORE_X_MODIFIER_WIN = _ecore_x_key_mask_get(XK_Super_L);
+ if (!ECORE_X_MODIFIER_WIN)
+ ECORE_X_MODIFIER_WIN = _ecore_x_key_mask_get(XK_Meta_L);
+
+ ECORE_X_MODIFIER_ALTGR = _ecore_x_key_mask_get(XK_Mode_switch);
+
+ if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT)
+ ECORE_X_MODIFIER_WIN = 0;
+
+ if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL)
+ ECORE_X_MODIFIER_ALT = 0;
+
+ ECORE_X_LOCK_SCROLL = _ecore_x_key_mask_get(XK_Scroll_Lock);
+ ECORE_X_LOCK_NUM = _ecore_x_key_mask_get(XK_Num_Lock);
+ ECORE_X_LOCK_CAPS = _ecore_x_key_mask_get(XK_Caps_Lock);
+ ECORE_X_LOCK_SHIFT = _ecore_x_key_mask_get(XK_Shift_Lock);
+}
+
+/**
+ * @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions
+ *
+ * Functions that start and shut down the Ecore X Library.
+ */
+
+/**
+ * Initialize the X display connection to the given display.
+ *
+ * @param name Display target name. If @c NULL, the default display is
+ * assumed.
+ * @return The number of times the library has been initialized without
+ * being shut down. 0 is returned if an error occurs.
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_init(const char *name)
+{
+ int shape_base = 0;
+ int shape_err_base = 0;
+#ifdef ECORE_XSS
+ int screensaver_base = 0;
+ int screensaver_err_base = 0;
+#endif /* ifdef ECORE_XSS */
+ int sync_base = 0;
+ int sync_err_base = 0;
+#ifdef ECORE_XRANDR
+ int randr_base = 0;
+ int randr_err_base = 0;
+#endif /* ifdef ECORE_XRANDR */
+#ifdef ECORE_XFIXES
+ int fixes_base = 0;
+ int fixes_err_base = 0;
+#endif /* ifdef ECORE_XFIXES */
+#ifdef ECORE_XDAMAGE
+ int damage_base = 0;
+ int damage_err_base = 0;
+#endif /* ifdef ECORE_XDAMAGE */
+#ifdef ECORE_XGESTURE
+ int gesture_base = 0;
+ int gesture_err_base = 0;
+#endif /* ifdef ECORE_XGESTURE */
+#ifdef ECORE_XKB
+ int xkb_base = 0;
+#endif /* ifdef ECORE_XKB */
+ if (++_ecore_x_init_count != 1)
+ return _ecore_x_init_count;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+#ifdef LOGRT
+ _logrt_init();
+#endif /* ifdef LOGRT */
+
+ eina_init();
+ _ecore_xlib_log_dom = eina_log_domain_register
+ ("ecore_x", ECORE_XLIB_DEFAULT_LOG_COLOR);
+ if (_ecore_xlib_log_dom < 0)
+ {
+ EINA_LOG_ERR(
+ "Impossible to create a log domain for the Ecore Xlib module.");
+ return --_ecore_x_init_count;
+ }
+
+ if (!ecore_init())
+ goto shutdown_eina;
+ if (!ecore_event_init())
+ goto shutdown_ecore;
+
+#ifdef EVAS_FRAME_QUEUING
+ XInitThreads();
+#endif /* ifdef EVAS_FRAME_QUEUING */
+ _ecore_x_disp = XOpenDisplay((char *)name);
+ if (!_ecore_x_disp)
+ goto shutdown_ecore_event;
+
+ _ecore_x_error_handler_init();
+ _ecore_x_event_handlers_num = LASTEvent;
+
+#define ECORE_X_EVENT_HANDLERS_GROW(ext_base, ext_num_events) \
+ do { \
+ if (_ecore_x_event_handlers_num < (ext_base + ext_num_events)) { \
+ _ecore_x_event_handlers_num = (ext_base + ext_num_events); } \
+ } while (0)
+
+ if (XShapeQueryExtension(_ecore_x_disp, &shape_base, &shape_err_base))
+ _ecore_x_event_shape_id = shape_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(shape_base, ShapeNumberEvents);
+
+#ifdef ECORE_XSS
+ if (XScreenSaverQueryExtension(_ecore_x_disp, &screensaver_base,
+ &screensaver_err_base))
+ _ecore_x_event_screensaver_id = screensaver_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(screensaver_base, ScreenSaverNumberEvents);
+#endif /* ifdef ECORE_XSS */
+
+ if (XSyncQueryExtension(_ecore_x_disp, &sync_base, &sync_err_base))
+ {
+ int major, minor;
+
+ _ecore_x_event_sync_id = sync_base;
+ if (!XSyncInitialize(_ecore_x_disp, &major, &minor))
+ _ecore_x_event_sync_id = 0;
+ }
+
+ ECORE_X_EVENT_HANDLERS_GROW(sync_base, XSyncNumberEvents);
+
+#ifdef ECORE_XRANDR
+ if (XRRQueryExtension(_ecore_x_disp, &randr_base, &randr_err_base))
+ _ecore_x_event_randr_id = randr_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(randr_base, RRNumberEvents);
+#endif /* ifdef ECORE_XRANDR */
+
+#ifdef ECORE_XFIXES
+ if (XFixesQueryExtension(_ecore_x_disp, &fixes_base, &fixes_err_base))
+ _ecore_x_event_fixes_selection_id = fixes_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(fixes_base, XFixesNumberEvents);
+#endif /* ifdef ECORE_XFIXES */
+
+#ifdef ECORE_XDAMAGE
+ if (XDamageQueryExtension(_ecore_x_disp, &damage_base, &damage_err_base))
+ _ecore_x_event_damage_id = damage_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(damage_base, XDamageNumberEvents);
+#endif /* ifdef ECORE_XDAMAGE */
+
+#ifdef ECORE_XGESTURE
+ if (XGestureQueryExtension(_ecore_x_disp, &gesture_base, &gesture_err_base))
+ _ecore_x_event_gesture_id = gesture_base;
+
+ ECORE_X_EVENT_HANDLERS_GROW(gesture_base, GestureNumberEvents);
+#endif /* ifdef ECORE_XGESTURE */
+#ifdef ECORE_XKB
+ {
+ int dummy;
+
+ if (XkbQueryExtension(_ecore_x_disp, &dummy, &xkb_base,
+ &dummy, &dummy, &dummy))
+ _ecore_x_event_xkb_id = xkb_base;
+ XkbSelectEventDetails(_ecore_x_disp, XkbUseCoreKbd, XkbStateNotify,
+ XkbAllStateComponentsMask, XkbGroupStateMask);
+ }
+ ECORE_X_EVENT_HANDLERS_GROW(xkb_base, XkbNumberEvents);
+#endif
+
+ _ecore_x_event_handlers = calloc(_ecore_x_event_handlers_num, sizeof(void *));
+ if (!_ecore_x_event_handlers)
+ goto close_display;
+
+#ifdef ECORE_XCURSOR
+ _ecore_x_xcursor = XcursorSupportsARGB(_ecore_x_disp) ? EINA_TRUE : EINA_FALSE;
+#endif /* ifdef ECORE_XCURSOR */
+ _ecore_x_event_handlers[AnyXEvent] = _ecore_x_event_handle_any_event;
+ _ecore_x_event_handlers[KeyPress] = _ecore_x_event_handle_key_press;
+ _ecore_x_event_handlers[KeyRelease] = _ecore_x_event_handle_key_release;
+ _ecore_x_event_handlers[ButtonPress] = _ecore_x_event_handle_button_press;
+ _ecore_x_event_handlers[ButtonRelease] =
+ _ecore_x_event_handle_button_release;
+ _ecore_x_event_handlers[MotionNotify] = _ecore_x_event_handle_motion_notify;
+ _ecore_x_event_handlers[EnterNotify] = _ecore_x_event_handle_enter_notify;
+ _ecore_x_event_handlers[LeaveNotify] = _ecore_x_event_handle_leave_notify;
+ _ecore_x_event_handlers[FocusIn] = _ecore_x_event_handle_focus_in;
+ _ecore_x_event_handlers[FocusOut] = _ecore_x_event_handle_focus_out;
+ _ecore_x_event_handlers[KeymapNotify] = _ecore_x_event_handle_keymap_notify;
+ _ecore_x_event_handlers[Expose] = _ecore_x_event_handle_expose;
+ _ecore_x_event_handlers[GraphicsExpose] =
+ _ecore_x_event_handle_graphics_expose;
+ _ecore_x_event_handlers[VisibilityNotify] =
+ _ecore_x_event_handle_visibility_notify;
+ _ecore_x_event_handlers[CreateNotify] = _ecore_x_event_handle_create_notify;
+ _ecore_x_event_handlers[DestroyNotify] =
+ _ecore_x_event_handle_destroy_notify;
+ _ecore_x_event_handlers[UnmapNotify] = _ecore_x_event_handle_unmap_notify;
+ _ecore_x_event_handlers[MapNotify] = _ecore_x_event_handle_map_notify;
+ _ecore_x_event_handlers[MapRequest] = _ecore_x_event_handle_map_request;
+ _ecore_x_event_handlers[ReparentNotify] =
+ _ecore_x_event_handle_reparent_notify;
+ _ecore_x_event_handlers[ConfigureNotify] =
+ _ecore_x_event_handle_configure_notify;
+ _ecore_x_event_handlers[ConfigureRequest] =
+ _ecore_x_event_handle_configure_request;
+ _ecore_x_event_handlers[GravityNotify] =
+ _ecore_x_event_handle_gravity_notify;
+ _ecore_x_event_handlers[ResizeRequest] =
+ _ecore_x_event_handle_resize_request;
+ _ecore_x_event_handlers[CirculateNotify] =
+ _ecore_x_event_handle_circulate_notify;
+ _ecore_x_event_handlers[CirculateRequest] =
+ _ecore_x_event_handle_circulate_request;
+ _ecore_x_event_handlers[PropertyNotify] =
+ _ecore_x_event_handle_property_notify;
+ _ecore_x_event_handlers[SelectionClear] =
+ _ecore_x_event_handle_selection_clear;
+ _ecore_x_event_handlers[SelectionRequest] =
+ _ecore_x_event_handle_selection_request;
+ _ecore_x_event_handlers[SelectionNotify] =
+ _ecore_x_event_handle_selection_notify;
+ _ecore_x_event_handlers[ColormapNotify] =
+ _ecore_x_event_handle_colormap_notify;
+ _ecore_x_event_handlers[ClientMessage] =
+ _ecore_x_event_handle_client_message;
+ _ecore_x_event_handlers[MappingNotify] =
+ _ecore_x_event_handle_mapping_notify;
+#ifdef GenericEvent
+ _ecore_x_event_handlers[GenericEvent] = _ecore_x_event_handle_generic_event;
+#endif /* ifdef GenericEvent */
+
+ if (_ecore_x_event_shape_id)
+ _ecore_x_event_handlers[_ecore_x_event_shape_id] =
+ _ecore_x_event_handle_shape_change;
+
+ if (_ecore_x_event_screensaver_id)
+ _ecore_x_event_handlers[_ecore_x_event_screensaver_id] =
+ _ecore_x_event_handle_screensaver_notify;
+
+ if (_ecore_x_event_sync_id)
+ {
+ _ecore_x_event_handlers[_ecore_x_event_sync_id + XSyncCounterNotify] =
+ _ecore_x_event_handle_sync_counter;
+ _ecore_x_event_handlers[_ecore_x_event_sync_id + XSyncAlarmNotify] =
+ _ecore_x_event_handle_sync_alarm;
+ }
+
+#ifdef ECORE_XRANDR
+ if (_ecore_x_event_randr_id)
+ {
+ _ecore_x_event_handlers[_ecore_x_event_randr_id +
+ RRScreenChangeNotify] =
+ _ecore_x_event_handle_randr_change;
+ _ecore_x_event_handlers[_ecore_x_event_randr_id +
+ RRNotify] = _ecore_x_event_handle_randr_notify;
+ }
+
+#endif /* ifdef ECORE_XRANDR */
+#ifdef ECORE_XFIXES
+ if (_ecore_x_event_fixes_selection_id)
+ _ecore_x_event_handlers[_ecore_x_event_fixes_selection_id] =
+ _ecore_x_event_handle_fixes_selection_notify;
+
+#endif /* ifdef ECORE_XFIXES */
+#ifdef ECORE_XDAMAGE
+ if (_ecore_x_event_damage_id)
+ _ecore_x_event_handlers[_ecore_x_event_damage_id] =
+ _ecore_x_event_handle_damage_notify;
+
+#endif /* ifdef ECORE_XDAMAGE */
+#ifdef ECORE_XKB
+ // set x autorepeat detection to on. that means instead of
+ // press-release-press-release-press-release
+ // you get
+ // press-press-press-press-press-release
+ do
+ {
+ Bool works = 0;
+ XkbSetDetectableAutoRepeat(_ecore_x_disp, 1, &works);
+ }
+ while (0);
+ if (_ecore_x_event_xkb_id)
+ _ecore_x_event_handlers[_ecore_x_event_xkb_id] = _ecore_x_event_handle_xkb;
+#endif /* ifdef ECORE_XKB */
+
+#ifdef ECORE_XGESTURE
+ if (_ecore_x_event_gesture_id)
+ {
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyFlick] =
+ _ecore_x_event_handle_gesture_notify_flick;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyPan] =
+ _ecore_x_event_handle_gesture_notify_pan;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyPinchRotation] =
+ _ecore_x_event_handle_gesture_notify_pinchrotation;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyTap] =
+ _ecore_x_event_handle_gesture_notify_tap;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyTapNHold] =
+ _ecore_x_event_handle_gesture_notify_tapnhold;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyHold] =
+ _ecore_x_event_handle_gesture_notify_hold;
+ _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyGroup] =
+ _ecore_x_event_handle_gesture_notify_group;
+ }
+
+#endif /* ifdef ECORE_XGESTURE */
+
+ if (!ECORE_X_EVENT_ANY)
+ {
+ ECORE_X_EVENT_ANY = ecore_event_type_new();
+ ECORE_X_EVENT_MOUSE_IN = ecore_event_type_new();
+ ECORE_X_EVENT_MOUSE_OUT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_KEYMAP = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_DAMAGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CREATE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_DESTROY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_HIDE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHOW = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHOW_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_REPARENT = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CONFIGURE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_GRAVITY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STACK = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STACK_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_PROPERTY = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_COLORMAP = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_MAPPING = ecore_event_type_new();
+ ECORE_X_EVENT_MAPPING_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_CLEAR = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_SELECTION_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_CLIENT_MESSAGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_SHAPE = ecore_event_type_new();
+ ECORE_X_EVENT_SCREENSAVER_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_PAN = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_TAP = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = ecore_event_type_new();
+ ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = ecore_event_type_new();
+ ECORE_X_EVENT_SYNC_COUNTER = ecore_event_type_new();
+ ECORE_X_EVENT_SYNC_ALARM = ecore_event_type_new();
+ ECORE_X_EVENT_SCREEN_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_CRTC_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_DAMAGE_NOTIFY = ecore_event_type_new();
+
+ ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
+
+ ECORE_X_EVENT_DESKTOP_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_WINDOW_STATE_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = ecore_event_type_new();
+ ECORE_X_EVENT_PING = ecore_event_type_new();
+
+ ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = ecore_event_type_new();
+ ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = ecore_event_type_new();
+ ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = ecore_event_type_new();
+
+ ECORE_X_EVENT_XKB_STATE_NOTIFY = ecore_event_type_new();
+ ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = ecore_event_type_new();
+
+ ECORE_X_EVENT_GENERIC = ecore_event_type_new();
+
+ ECORE_X_RAW_BUTTON_PRESS = ecore_event_type_new();
+ ECORE_X_RAW_BUTTON_RELEASE = ecore_event_type_new();
+ ECORE_X_RAW_MOTION = ecore_event_type_new();
+ }
+
+ _ecore_x_modifiers_get();
+
+ _ecore_x_fd_handler_handle =
+ ecore_main_fd_handler_add(ConnectionNumber(_ecore_x_disp),
+ ECORE_FD_READ,
+ _ecore_x_fd_handler, _ecore_x_disp,
+ _ecore_x_fd_handler_buf, _ecore_x_disp);
+ if (!_ecore_x_fd_handler_handle)
+ goto free_event_handlers;
+
+ _ecore_x_atoms_init();
+
+ /* Set up the ICCCM hints */
+ ecore_x_icccm_init();
+
+ /* Set up the _NET_... hints */
+ ecore_x_netwm_init();
+
+ /* old e hints init */
+ ecore_x_e_init();
+
+ /* This is just to be anal about naming conventions */
+
+ _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] =
+ ECORE_X_ATOM_WM_DELETE_WINDOW;
+ _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] =
+ ECORE_X_ATOM_WM_TAKE_FOCUS;
+ _ecore_x_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_PING] =
+ ECORE_X_ATOM_NET_WM_PING;
+ _ecore_x_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] =
+ ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+
+ _ecore_x_selection_data_init();
+ _ecore_x_dnd_init();
+ _ecore_x_fixes_init();
+ _ecore_x_damage_init();
+ _ecore_x_composite_init();
+ _ecore_x_dpms_init();
+ _ecore_x_randr_init();
+ _ecore_x_gesture_init();
+ _ecore_x_input_init();
+ _ecore_x_events_init();
+
+ _ecore_x_private_win = ecore_x_window_override_new(0, -77, -777, 123, 456);
+
+ return _ecore_x_init_count;
+
+free_event_handlers:
+ free(_ecore_x_event_handlers);
+ _ecore_x_event_handlers = NULL;
+close_display:
+ XCloseDisplay(_ecore_x_disp);
+ _ecore_x_fd_handler_handle = NULL;
+ _ecore_x_disp = NULL;
+shutdown_ecore_event:
+ ecore_event_shutdown();
+shutdown_ecore:
+ ecore_shutdown();
+shutdown_eina:
+ eina_log_domain_unregister(_ecore_xlib_log_dom);
+ _ecore_xlib_log_dom = -1;
+ eina_shutdown();
+
+ return --_ecore_x_init_count;
+}
+
+static int
+_ecore_x_shutdown(int close_display)
+{
+ if (--_ecore_x_init_count != 0)
+ return _ecore_x_init_count;
+
+ if (!_ecore_x_disp)
+ return _ecore_x_init_count;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ ecore_main_fd_handler_del(_ecore_x_fd_handler_handle);
+ if (close_display)
+ XCloseDisplay(_ecore_x_disp);
+ else
+ {
+ close(ConnectionNumber(_ecore_x_disp));
+ // FIXME: may have to clean up x display internal here
+// getting segv here? hmmm. odd. disable
+// XFree(_ecore_x_disp);
+ }
+
+ free(_ecore_x_event_handlers);
+ _ecore_x_fd_handler_handle = NULL;
+ _ecore_x_disp = NULL;
+ _ecore_x_event_handlers = NULL;
+ _ecore_x_events_shutdown();
+ _ecore_x_input_shutdown();
+ _ecore_x_selection_shutdown();
+ _ecore_x_dnd_shutdown();
+ ecore_x_netwm_shutdown();
+
+ ecore_event_shutdown();
+ ecore_shutdown();
+
+ eina_log_domain_unregister(_ecore_xlib_log_dom);
+ _ecore_xlib_log_dom = -1;
+ eina_shutdown();
+
+ return _ecore_x_init_count;
+}
+
+/**
+ * Shuts down the Ecore X library.
+ *
+ * In shutting down the library, the X display connection is terminated
+ * and any event handlers for it are removed.
+ *
+ * @return The number of times the library has been initialized without
+ * being shut down. 0 is returned if an error occurs.
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_shutdown(void)
+{
+ return _ecore_x_shutdown(1);
+}
+
+/**
+ * Shuts down the Ecore X library.
+ *
+ * As ecore_x_shutdown, except do not close Display, only connection.
+ *
+ * @ingroup Ecore_X_Init_Group
+ */
+EAPI int
+ecore_x_disconnect(void)
+{
+ return _ecore_x_shutdown(0);
+}
+
+/**
+ * @defgroup Ecore_X_Display_Attr_Group X Display Attributes
+ *
+ * Functions that set and retrieve X display attributes.
+ */
+
+/**
+ * Retrieves the Ecore_X_Display handle used for the current X connection.
+ * @return The current X display.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI Ecore_X_Display *
+ecore_x_display_get(void)
+{
+ return (Ecore_X_Display *)_ecore_x_disp;
+}
+
+/**
+ * Retrieves the X display file descriptor.
+ * @return The current X display file descriptor.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI int
+ecore_x_fd_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ConnectionNumber(_ecore_x_disp);
+}
+
+/**
+ * Retrieves the Ecore_X_Screen handle used for the current X connection.
+ * @return The current default screen.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI Ecore_X_Screen *
+ecore_x_default_screen_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return (Ecore_X_Screen *)DefaultScreenOfDisplay(_ecore_x_disp);
+}
+
+/**
+ * Retrieves the size of an Ecore_X_Screen.
+ * @param screen the handle to the screen to query.
+ * @param w where to return the width. May be NULL. Returns 0 on errors.
+ * @param h where to return the height. May be NULL. Returns 0 on errors.
+ * @ingroup Ecore_X_Display_Attr_Group
+ * @see ecore_x_default_screen_get()
+ *
+ * @since 1.1
+ */
+EAPI void
+ecore_x_screen_size_get(const Ecore_X_Screen *screen,
+ int *w,
+ int *h)
+{
+ Screen *s = (Screen *)screen;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (!s) return;
+ if (w) *w = s->width;
+ if (h) *h = s->height;
+}
+
+/**
+ * Retrieves the number of screens.
+ *
+ * @return The count of the number of screens.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI int
+ecore_x_screen_count_get(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ return ScreenCount(_ecore_x_disp);
+}
+
+/**
+ * Retrieves the index number of the given screen.
+ *
+ * @param screen The screen for which the index will be retrieved.
+ * @return The index number of the screen.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI int
+ecore_x_screen_index_get(const Ecore_X_Screen *screen)
+{
+ return XScreenNumberOfScreen((Screen *)screen);
+}
+
+/**
+ * Retrieves the screen based on index number.
+ *
+ * @param idx The index that will be used to retrieve the screen.
+ * @return The Ecore_X_Screen at this index.
+ * @ingroup Ecore_X_Display_Attr_Group
+ *
+ * @since 1.1
+ */
+EAPI Ecore_X_Screen *
+ecore_x_screen_get(int idx)
+{
+ return XScreenOfDisplay(_ecore_x_disp, idx);
+}
+
+/**
+ * Sets the timeout for a double and triple clicks to be flagged.
+ *
+ * This sets the time between clicks before the double_click flag is
+ * set in a button down event. If 3 clicks occur within double this
+ * time, the triple_click flag is also set.
+ *
+ * @param t The time in seconds
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI void
+ecore_x_double_click_time_set(double t)
+{
+ if (t < 0.0)
+ t = 0.0;
+
+ _ecore_x_double_click_time = t;
+}
+
+/**
+ * Retrieves the double and triple click flag timeout.
+ *
+ * See @ref ecore_x_double_click_time_set for more information.
+ *
+ * @return The timeout for double clicks in seconds.
+ * @ingroup Ecore_X_Display_Attr_Group
+ */
+EAPI double
+ecore_x_double_click_time_get(void)
+{
+ return _ecore_x_double_click_time;
+}
+
+/**
+ * @defgroup Ecore_X_Flush_Group X Synchronization Functions
+ *
+ * Functions that ensure that all commands that have been issued by the
+ * Ecore X library have been sent to the server.
+ */
+
+/**
+ * Sends all X commands in the X Display buffer.
+ * @ingroup Ecore_X_Flush_Group
+ */
+EAPI void
+ecore_x_flush(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFlush(_ecore_x_disp);
+}
+
+/**
+ * Flushes the command buffer and waits until all requests have been
+ * processed by the server.
+ * @ingroup Ecore_X_Flush_Group
+ */
+EAPI void
+ecore_x_sync(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSync(_ecore_x_disp, False);
+}
+
+/**
+ * Kill all clients with subwindows under a given window.
+ *
+ * You can kill all clients connected to the X server by using
+ * @ref ecore_x_window_root_list to get a list of root windows, and
+ * then passing each root window to this function.
+ *
+ * @param root The window whose children will be killed.
+ */
+EAPI void
+ecore_x_killall(Ecore_X_Window root)
+{
+ unsigned int j;
+ Window root_r;
+ Window parent_r;
+ Window *children_r = NULL;
+ unsigned int num_children = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGrabServer(_ecore_x_disp);
+ /* Tranverse window tree starting from root, and drag each
+ * before the firing squad */
+ while (XQueryTree(_ecore_x_disp, root, &root_r, &parent_r,
+ &children_r, &num_children) && (num_children > 0))
+ {
+ for (j = 0; j < num_children; ++j)
+ {
+ XKillClient(_ecore_x_disp, children_r[j]);
+ }
+
+ XFree(children_r);
+ }
+ XUngrabServer(_ecore_x_disp);
+ XSync(_ecore_x_disp, False);
+}
+
+/**
+ * Kill a specific client
+ *
+ * You can kill a specific client owning window @p win
+ *
+ * @param win Window of the client to be killed
+ */
+EAPI void
+ecore_x_kill(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XKillClient(_ecore_x_disp, win);
+}
+
+/**
+ * Return the last event time
+ */
+EAPI Ecore_X_Time
+ecore_x_current_time_get(void)
+{
+ return _ecore_x_event_last_time;
+}
+
+/**
+ * Return the screen DPI
+ *
+ * This is a simplistic call to get DPI. It does not account for differing
+ * DPI in the x amd y axes nor does it account for multihead or xinerama and
+ * xrander where different parts of the screen may have different DPI etc.
+ *
+ * @return the general screen DPI (dots/pixels per inch).
+ */
+EAPI int
+ecore_x_dpi_get(void)
+{
+ Screen *s;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ s = DefaultScreenOfDisplay(_ecore_x_disp);
+ if (s->mwidth <= 0)
+ return 75;
+
+ return (((s->width * 254) / s->mwidth) + 5) / 10;
+}
+
+/**
+ * Invoke the standard system beep to alert users
+ *
+ * @param percent The volume at which the bell rings. Must be in the range
+ * [-100,+100]. If percent >= 0, the final volume will be:
+ * base - [(base * percent) / 100] + percent
+ * Otherwise, it's calculated as:
+ * base + [(base * percent) / 100]
+ * where @c base is the bell's base volume as set by XChangeKeyboardControl(3).
+ *
+ * @returns @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_bell(int percent)
+{
+ int ret;
+
+ ret = XBell(_ecore_x_disp, percent);
+ if (ret == BadValue)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_fd_handler(void *data,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Display *d;
+
+ d = data;
+ while (XPending(d))
+ {
+ XEvent ev;
+
+ XNextEvent(d, &ev);
+#ifdef ENABLE_XIM
+ /* Filter event for XIM */
+ if (XFilterEvent(&ev, ev.xkey.window))
+ continue;
+
+#endif /* ifdef ENABLE_XIM */
+ if ((ev.type >= 0) && (ev.type < _ecore_x_event_handlers_num))
+ {
+ if (_ecore_x_event_handlers[AnyXEvent])
+ _ecore_x_event_handlers[AnyXEvent] (&ev);
+
+ if (_ecore_x_event_handlers[ev.type])
+ _ecore_x_event_handlers[ev.type] (&ev);
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_x_fd_handler_buf(void *data,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ Display *d;
+
+ d = data;
+ if (XPending(d))
+ return ECORE_CALLBACK_RENEW;
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int
+_ecore_x_key_mask_get(KeySym sym)
+{
+ XModifierKeymap *mod;
+ KeySym sym2;
+ int i, j;
+ const int masks[8] =
+ {
+ ShiftMask, LockMask, ControlMask,
+ Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+ };
+
+ mod = XGetModifierMapping(_ecore_x_disp);
+ if ((mod) && (mod->max_keypermod > 0))
+ for (i = 0; i < (8 * mod->max_keypermod); i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ sym2 = _ecore_x_XKeycodeToKeysym(_ecore_x_disp,
+ mod->modifiermap[i], j);
+ if (sym2 != 0)
+ break;
+ }
+ if (sym2 == sym)
+ {
+ int mask;
+
+ mask = masks[i / mod->max_keypermod];
+ if (mod->modifiermap)
+ XFree(mod->modifiermap);
+
+ XFree(mod);
+ return mask;
+ }
+ }
+
+ if (mod)
+ {
+ if (mod->modifiermap)
+ XFree(mod->modifiermap);
+
+ XFree(mod);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/* FIXME: these funcs need categorising */
+/*****************************************************************************/
+
+/**
+ * Get a list of all the root windows on the server.
+ *
+ * @note The returned array will need to be freed after use.
+ * @param num_ret Pointer to integer to put number of windows returned in.
+ * @return An array of all the root windows. @c NULL is returned if memory
+ * could not be allocated for the list, or if @p num_ret is @c NULL.
+ */
+EAPI Ecore_X_Window *
+ecore_x_window_root_list(int *num_ret)
+{
+ int num, i;
+ Ecore_X_Window *roots;
+#ifdef ECORE_XPRINT
+ int xp_base, xp_err_base;
+#endif /* ifdef ECORE_XPRINT */
+
+ if (!num_ret)
+ return NULL;
+
+ *num_ret = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+#ifdef ECORE_XPRINT
+ num = ScreenCount(_ecore_x_disp);
+ if (XpQueryExtension(_ecore_x_disp, &xp_base, &xp_err_base))
+ {
+ Screen **ps = NULL;
+ int psnum = 0;
+
+ ps = XpQueryScreens(_ecore_x_disp, &psnum);
+ if (ps)
+ {
+ int overlap, j;
+
+ overlap = 0;
+ for (i = 0; i < num; i++)
+ {
+ for (j = 0; j < psnum; j++)
+ {
+ if (ScreenOfDisplay(_ecore_x_disp, i) == ps[j])
+ overlap++;
+ }
+ }
+ roots = malloc(MAX((num - overlap) * sizeof(Window), 1));
+ if (roots)
+ {
+ int k;
+
+ k = 0;
+ for (i = 0; i < num; i++)
+ {
+ int is_print;
+
+ is_print = 0;
+ for (j = 0; j < psnum; j++)
+ {
+ if (ScreenOfDisplay(_ecore_x_disp, i) == ps[j])
+ {
+ is_print = 1;
+ break;
+ }
+ }
+ if (!is_print)
+ {
+ roots[k] = RootWindow(_ecore_x_disp, i);
+ k++;
+ }
+ }
+ *num_ret = k;
+ }
+
+ XFree(ps);
+ }
+ else
+ {
+ roots = malloc(num * sizeof(Window));
+ if (!roots)
+ return NULL;
+
+ *num_ret = num;
+ for (i = 0; i < num; i++)
+ roots[i] = RootWindow(_ecore_x_disp, i);
+ }
+ }
+ else
+ {
+ roots = malloc(num * sizeof(Window));
+ if (!roots)
+ return NULL;
+
+ *num_ret = num;
+ for (i = 0; i < num; i++)
+ roots[i] = RootWindow(_ecore_x_disp, i);
+ }
+
+#else /* ifdef ECORE_XPRINT */
+ num = ScreenCount(_ecore_x_disp);
+ roots = malloc(num * sizeof(Window));
+ if (!roots)
+ return NULL;
+
+ *num_ret = num;
+ for (i = 0; i < num; i++)
+ roots[i] = RootWindow(_ecore_x_disp, i);
+#endif /* ifdef ECORE_XPRINT */
+ return roots;
+}
+
+EAPI Ecore_X_Window
+ecore_x_window_root_first_get(void)
+{
+ return RootWindow(_ecore_x_disp, 0);
+/*
+ int num;
+ Ecore_X_Window root, *roots = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ roots = ecore_x_window_root_list(&num);
+ if (!(roots)) return 0;
+
+ if (num > 0)
+ root = roots[0];
+ else
+ root = 0;
+
+ free(roots);
+ return root;
+ */
+}
+
+static void _ecore_x_window_manage_error(void *data);
+
+static int _ecore_x_window_manage_failed = 0;
+static void
+_ecore_x_window_manage_error(void *data EINA_UNUSED)
+{
+ if ((ecore_x_error_request_get() == X_ChangeWindowAttributes) &&
+ (ecore_x_error_code_get() == BadAccess))
+ _ecore_x_window_manage_failed = 1;
+}
+
+EAPI Eina_Bool
+ecore_x_window_manage(Ecore_X_Window win)
+{
+ XWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XGetWindowAttributes(_ecore_x_disp, win, &att) != True)
+ return EINA_FALSE;
+
+ ecore_x_sync();
+ _ecore_x_window_manage_failed = 0;
+ ecore_x_error_handler_set(_ecore_x_window_manage_error, NULL);
+ XSelectInput(_ecore_x_disp, win,
+ EnterWindowMask |
+ LeaveWindowMask |
+ PropertyChangeMask |
+ ResizeRedirectMask |
+ SubstructureRedirectMask |
+ SubstructureNotifyMask |
+ StructureNotifyMask |
+ KeyPressMask |
+ KeyReleaseMask |
+ att.your_event_mask);
+ ecore_x_sync();
+ ecore_x_error_handler_set(NULL, NULL);
+ if (_ecore_x_window_manage_failed)
+ {
+ _ecore_x_window_manage_failed = 0;
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_window_container_manage(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSelectInput(_ecore_x_disp, win,
+ SubstructureRedirectMask |
+ SubstructureNotifyMask);
+}
+
+EAPI void
+ecore_x_window_client_manage(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSelectInput(_ecore_x_disp, win,
+ PropertyChangeMask |
+// ResizeRedirectMask |
+ FocusChangeMask |
+ ColormapChangeMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask
+ );
+ XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask);
+}
+
+EAPI void
+ecore_x_window_sniff(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSelectInput(_ecore_x_disp, win,
+ PropertyChangeMask |
+ SubstructureNotifyMask);
+}
+
+EAPI void
+ecore_x_window_client_sniff(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSelectInput(_ecore_x_disp, win,
+ PropertyChangeMask |
+ FocusChangeMask |
+ ColormapChangeMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask);
+ XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask);
+}
+
+EAPI Eina_Bool
+ecore_x_window_attributes_get(Ecore_X_Window win,
+ Ecore_X_Window_Attributes *att_ret)
+{
+ XWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetWindowAttributes(_ecore_x_disp, win, &att))
+ return EINA_FALSE;
+
+ memset(att_ret, 0, sizeof(Ecore_X_Window_Attributes));
+ att_ret->root = att.root;
+ att_ret->x = att.x;
+ att_ret->y = att.y;
+ att_ret->w = att.width;
+ att_ret->h = att.height;
+ att_ret->border = att.border_width;
+ att_ret->depth = att.depth;
+ if (att.map_state != IsUnmapped)
+ att_ret->visible = 1;
+
+ if (att.map_state == IsViewable)
+ att_ret->viewable = 1;
+
+ if (att.override_redirect)
+ att_ret->override = 1;
+
+ if (att.class == InputOnly)
+ att_ret->input_only = 1;
+
+ if (att.save_under)
+ att_ret->save_under = 1;
+
+ att_ret->event_mask.mine = att.your_event_mask;
+ att_ret->event_mask.all = att.all_event_masks;
+ att_ret->event_mask.no_propagate = att.do_not_propagate_mask;
+ att_ret->window_gravity = att.win_gravity;
+ att_ret->pixel_gravity = att.bit_gravity;
+ att_ret->colormap = att.colormap;
+ att_ret->visual = att.visual;
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_window_save_set_add(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XAddToSaveSet(_ecore_x_disp, win);
+}
+
+EAPI void
+ecore_x_window_save_set_del(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XRemoveFromSaveSet(_ecore_x_disp, win);
+}
+
+EAPI Ecore_X_Window *
+ecore_x_window_children_get(Ecore_X_Window win,
+ int *num)
+{
+ Ecore_X_Window *windows = NULL;
+ Window root_ret = 0, parent_ret = 0, *children_ret = NULL;
+ unsigned int children_ret_num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XQueryTree(_ecore_x_disp, win, &root_ret, &parent_ret, &children_ret,
+ &children_ret_num))
+ return NULL;
+
+ if (children_ret)
+ {
+ windows = malloc(children_ret_num * sizeof(Ecore_X_Window));
+ if (windows)
+ {
+ unsigned int i;
+
+ for (i = 0; i < children_ret_num; i++)
+ windows[i] = children_ret[i];
+ *num = children_ret_num;
+ }
+
+ XFree(children_ret);
+ }
+
+ return windows;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_control_set(int accel_num,
+ int accel_denom,
+ int threshold)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XChangePointerControl(_ecore_x_disp, 1, 1,
+ accel_num, accel_denom, threshold) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_control_get(int *accel_num,
+ int *accel_denom,
+ int *threshold)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XGetPointerControl(_ecore_x_disp,
+ accel_num, accel_denom, threshold) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_mapping_set(unsigned char *map,
+ int nmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return (XSetPointerMapping(_ecore_x_disp, map, nmap) == MappingSuccess) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_mapping_get(unsigned char *map,
+ int nmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XGetPointerMapping(_ecore_x_disp, map, nmap) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_grab(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XGrabPointer(_ecore_x_disp, win, False,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ None, None, CurrentTime) == GrabSuccess)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_confine_grab(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XGrabPointer(_ecore_x_disp, win, False,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ win, None, CurrentTime) == GrabSuccess)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_pointer_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XUngrabPointer(_ecore_x_disp, CurrentTime);
+}
+
+EAPI Eina_Bool
+ecore_x_pointer_warp(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XWarpPointer(_ecore_x_disp, None, win, 0, 0, 0, 0, x, y) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_keyboard_grab(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XGrabKeyboard(_ecore_x_disp, win, False,
+ GrabModeAsync, GrabModeAsync,
+ CurrentTime) == GrabSuccess)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_keyboard_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XUngrabKeyboard(_ecore_x_disp, CurrentTime);
+}
+
+EAPI void
+ecore_x_grab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_grab_count++;
+ if (_ecore_x_grab_count == 1)
+ XGrabServer(_ecore_x_disp);
+}
+
+EAPI void
+ecore_x_ungrab(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_grab_count--;
+ if (_ecore_x_grab_count < 0)
+ _ecore_x_grab_count = 0;
+
+ if (_ecore_x_grab_count == 0)
+ XUngrabServer(_ecore_x_disp);
+}
+
+int _ecore_window_grabs_num = 0;
+Window *_ecore_window_grabs = NULL;
+Eina_Bool (*_ecore_window_grab_replay_func)(void *data,
+ int event_type,
+ void *event);
+void *_ecore_window_grab_replay_data;
+
+EAPI void
+ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data,
+ int event_type,
+ void *event),
+ void *data)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_window_grab_replay_func = func;
+ _ecore_window_grab_replay_data = data;
+}
+
+EAPI void
+ecore_x_window_button_grab(Ecore_X_Window win,
+ int button,
+ Ecore_X_Event_Mask event_mask,
+ int mod,
+ int any_mod)
+{
+ unsigned int b;
+ unsigned int m;
+ unsigned int locks[8];
+ int i, ev;
+ Window *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ b = button;
+ if (b == 0)
+ b = AnyButton;
+
+ m = _ecore_x_event_modifier(mod);
+ if (any_mod)
+ m = AnyModifier;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ ev = event_mask;
+ for (i = 0; i < 8; i++)
+ XGrabButton(_ecore_x_disp, b, m | locks[i],
+ win, False, ev, GrabModeSync, GrabModeAsync, None, None);
+ _ecore_window_grabs_num++;
+ t = realloc(_ecore_window_grabs,
+ _ecore_window_grabs_num * sizeof(Window));
+ if (!t) return;
+ _ecore_window_grabs = t;
+ _ecore_window_grabs[_ecore_window_grabs_num - 1] = win;
+}
+
+void
+_ecore_x_sync_magic_send(int val,
+ Ecore_X_Window swin)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = _ecore_x_private_win;
+ xev.xclient.format = 32;
+ xev.xclient.message_type = 27777;
+ xev.xclient.data.l[0] = 0x7162534;
+ xev.xclient.data.l[1] = 0x10000000 + val;
+ xev.xclient.data.l[2] = swin;
+ XSendEvent(_ecore_x_disp, _ecore_x_private_win, False, NoEventMask, &xev);
+}
+
+void
+_ecore_x_window_grab_remove(Ecore_X_Window win)
+{
+ int i, shuffle = 0;
+ Window *t;
+
+ if (_ecore_window_grabs_num > 0)
+ {
+ for (i = 0; i < _ecore_window_grabs_num; i++)
+ {
+ if (shuffle)
+ _ecore_window_grabs[i - 1] = _ecore_window_grabs[i];
+
+ if ((!shuffle) && (_ecore_window_grabs[i] == win))
+ shuffle = 1;
+ }
+ if (shuffle)
+ {
+ _ecore_window_grabs_num--;
+ if (_ecore_window_grabs_num <= 0)
+ {
+ free(_ecore_window_grabs);
+ _ecore_window_grabs = NULL;
+ return;
+ }
+ t = realloc(_ecore_window_grabs,
+ _ecore_window_grabs_num *
+ sizeof(Window));
+ if (!t) return;
+ _ecore_window_grabs = t;
+ }
+ }
+}
+
+EAPI void
+ecore_x_window_button_ungrab(Ecore_X_Window win,
+ int button,
+ int mod,
+ int any_mod)
+{
+ unsigned int b;
+ unsigned int m;
+ unsigned int locks[8];
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ b = button;
+ if (b == 0)
+ b = AnyButton;
+
+ m = _ecore_x_event_modifier(mod);
+ if (any_mod)
+ m = AnyModifier;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ for (i = 0; i < 8; i++)
+ XUngrabButton(_ecore_x_disp, b, m | locks[i], win);
+ _ecore_x_sync_magic_send(1, win);
+}
+
+int _ecore_key_grabs_num = 0;
+Window *_ecore_key_grabs = NULL;
+
+EAPI void
+ecore_x_window_key_grab(Ecore_X_Window win,
+ const char *key,
+ int mod,
+ int any_mod)
+{
+ KeyCode keycode = 0;
+ KeySym keysym;
+ unsigned int m;
+ unsigned int locks[8];
+ int i;
+ Window *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ return;
+
+ keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key));
+ }
+
+ if (keycode == 0)
+ return;
+
+ m = _ecore_x_event_modifier(mod);
+ if (any_mod)
+ m = AnyModifier;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ for (i = 0; i < 8; i++)
+ XGrabKey(_ecore_x_disp, keycode, m | locks[i],
+ win, False, GrabModeSync, GrabModeAsync);
+ _ecore_key_grabs_num++;
+ t = realloc(_ecore_key_grabs,
+ _ecore_key_grabs_num * sizeof(Window));
+ if (!t) return;
+ _ecore_key_grabs = t;
+ _ecore_key_grabs[_ecore_key_grabs_num - 1] = win;
+}
+
+void
+_ecore_x_key_grab_remove(Ecore_X_Window win)
+{
+ int i, shuffle = 0;
+ Window *t;
+
+ if (_ecore_key_grabs_num > 0)
+ {
+ for (i = 0; i < _ecore_key_grabs_num; i++)
+ {
+ if (shuffle)
+ _ecore_key_grabs[i - 1] = _ecore_key_grabs[i];
+
+ if ((!shuffle) && (_ecore_key_grabs[i] == win))
+ shuffle = 1;
+ }
+ if (shuffle)
+ {
+ _ecore_key_grabs_num--;
+ if (_ecore_key_grabs_num <= 0)
+ {
+ free(_ecore_key_grabs);
+ _ecore_key_grabs = NULL;
+ return;
+ }
+ t = realloc(_ecore_key_grabs,
+ _ecore_key_grabs_num * sizeof(Window));
+ if (!t) return;
+ _ecore_key_grabs = t;
+ }
+ }
+}
+
+EAPI void
+ecore_x_window_key_ungrab(Ecore_X_Window win,
+ const char *key,
+ int mod,
+ int any_mod)
+{
+ KeyCode keycode = 0;
+ KeySym keysym;
+ unsigned int m;
+ unsigned int locks[8];
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ return;
+
+ keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key));
+ }
+
+ if (keycode == 0)
+ return;
+
+ m = _ecore_x_event_modifier(mod);
+ if (any_mod)
+ m = AnyModifier;
+
+ locks[0] = 0;
+ locks[1] = ECORE_X_LOCK_CAPS;
+ locks[2] = ECORE_X_LOCK_NUM;
+ locks[3] = ECORE_X_LOCK_SCROLL;
+ locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM;
+ locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL;
+ locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL;
+ for (i = 0; i < 8; i++)
+ XUngrabKey(_ecore_x_disp, keycode, m | locks[i], win);
+ _ecore_x_sync_magic_send(2, win);
+}
+
+/**
+ * Send client message with given type and format 32.
+ *
+ * @param win The window the message is sent to.
+ * @param type The client message type.
+ * @param mask The mask of the message to be sent.
+ * @param d0 The client message data item 1
+ * @param d1 The client message data item 2
+ * @param d2 The client message data item 3
+ * @param d3 The client message data item 4
+ * @param d4 The client message data item 5
+ *
+ * @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_client_message32_send(Ecore_X_Window win,
+ Ecore_X_Atom type,
+ Ecore_X_Event_Mask mask,
+ long d0,
+ long d1,
+ long d2,
+ long d3,
+ long d4)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.window = win;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = type;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = d0;
+ xev.xclient.data.l[1] = d1;
+ xev.xclient.data.l[2] = d2;
+ xev.xclient.data.l[3] = d3;
+ xev.xclient.data.l[4] = d4;
+
+ return XSendEvent(_ecore_x_disp, win, False, mask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * Send client message with given type and format 8.
+ *
+ * @param win The window the message is sent to.
+ * @param type The client message type.
+ * @param data Data to be sent.
+ * @param len Number of data bytes, max @c 20.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_client_message8_send(Ecore_X_Window win,
+ Ecore_X_Atom type,
+ const void *data,
+ int len)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.window = win;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = type;
+ xev.xclient.format = 8;
+ if (len > 20)
+ len = 20;
+
+ memcpy(xev.xclient.data.b, data, len);
+ memset(xev.xclient.data.b + len, 0, 20 - len);
+
+ return XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_move_send(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ XEvent xev;
+ XWindowAttributes att;
+ Window tw;
+ int rx, ry;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetWindowAttributes(_ecore_x_disp, win, &att);
+ XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw);
+ xev.xmotion.type = MotionNotify;
+ xev.xmotion.window = win;
+ xev.xmotion.root = att.root;
+ xev.xmotion.subwindow = win;
+ xev.xmotion.time = _ecore_x_event_last_time;
+ xev.xmotion.x = x;
+ xev.xmotion.y = y;
+ xev.xmotion.x_root = rx;
+ xev.xmotion.y_root = ry;
+ xev.xmotion.state = 0;
+ xev.xmotion.is_hint = 0;
+ xev.xmotion.same_screen = 1;
+ return XSendEvent(_ecore_x_disp, win, True, PointerMotionMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_down_send(Ecore_X_Window win,
+ int x,
+ int y,
+ int b)
+{
+ XEvent xev;
+ XWindowAttributes att;
+ Window tw;
+ int rx, ry;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetWindowAttributes(_ecore_x_disp, win, &att);
+ XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw);
+ xev.xbutton.type = ButtonPress;
+ xev.xbutton.window = win;
+ xev.xbutton.root = att.root;
+ xev.xbutton.subwindow = win;
+ xev.xbutton.time = _ecore_x_event_last_time;
+ xev.xbutton.x = x;
+ xev.xbutton.y = y;
+ xev.xbutton.x_root = rx;
+ xev.xbutton.y_root = ry;
+ xev.xbutton.state = 1 << b;
+ xev.xbutton.button = b;
+ xev.xbutton.same_screen = 1;
+ return XSendEvent(_ecore_x_disp, win, True, ButtonPressMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_up_send(Ecore_X_Window win,
+ int x,
+ int y,
+ int b)
+{
+ XEvent xev;
+ XWindowAttributes att;
+ Window tw;
+ int rx, ry;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetWindowAttributes(_ecore_x_disp, win, &att);
+ XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw);
+ xev.xbutton.type = ButtonRelease;
+ xev.xbutton.window = win;
+ xev.xbutton.root = att.root;
+ xev.xbutton.subwindow = win;
+ xev.xbutton.time = _ecore_x_event_last_time;
+ xev.xbutton.x = x;
+ xev.xbutton.y = y;
+ xev.xbutton.x_root = rx;
+ xev.xbutton.y_root = ry;
+ xev.xbutton.state = 0;
+ xev.xbutton.button = b;
+ xev.xbutton.same_screen = 1;
+ return XSendEvent(_ecore_x_disp, win, True, ButtonReleaseMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_in_send(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ XEvent xev;
+ XWindowAttributes att;
+ Window tw;
+ int rx, ry;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetWindowAttributes(_ecore_x_disp, win, &att);
+ XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw);
+ xev.xcrossing.type = EnterNotify;
+ xev.xcrossing.window = win;
+ xev.xcrossing.root = att.root;
+ xev.xcrossing.subwindow = win;
+ xev.xcrossing.time = _ecore_x_event_last_time;
+ xev.xcrossing.x = x;
+ xev.xcrossing.y = y;
+ xev.xcrossing.x_root = rx;
+ xev.xcrossing.y_root = ry;
+ xev.xcrossing.mode = NotifyNormal;
+ xev.xcrossing.detail = NotifyNonlinear;
+ xev.xcrossing.same_screen = 1;
+ xev.xcrossing.focus = 0;
+ xev.xcrossing.state = 0;
+ return XSendEvent(_ecore_x_disp, win, True, EnterWindowMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_mouse_out_send(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ XEvent xev;
+ XWindowAttributes att;
+ Window tw;
+ int rx, ry;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetWindowAttributes(_ecore_x_disp, win, &att);
+ XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw);
+ xev.xcrossing.type = LeaveNotify;
+ xev.xcrossing.window = win;
+ xev.xcrossing.root = att.root;
+ xev.xcrossing.subwindow = win;
+ xev.xcrossing.time = _ecore_x_event_last_time;
+ xev.xcrossing.x = x;
+ xev.xcrossing.y = y;
+ xev.xcrossing.x_root = rx;
+ xev.xcrossing.y_root = ry;
+ xev.xcrossing.mode = NotifyNormal;
+ xev.xcrossing.detail = NotifyNonlinear;
+ xev.xcrossing.same_screen = 1;
+ xev.xcrossing.focus = 0;
+ xev.xcrossing.state = 0;
+ return XSendEvent(_ecore_x_disp, win, True, LeaveWindowMask, &xev) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_focus_reset(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSetInputFocus(_ecore_x_disp, PointerRoot, RevertToPointerRoot, CurrentTime);
+}
+
+EAPI void
+ecore_x_events_allow_all(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XAllowEvents(_ecore_x_disp, AsyncBoth, CurrentTime);
+}
+
+EAPI void
+ecore_x_pointer_last_xy_get(int *x,
+ int *y)
+{
+ if (x)
+ *x = _ecore_x_event_last_root_x;
+
+ if (y)
+ *y = _ecore_x_event_last_root_y;
+}
+
+EAPI void
+ecore_x_pointer_xy_get(Ecore_X_Window win,
+ int *x,
+ int *y)
+{
+ Window rwin, cwin;
+ int rx, ry, wx, wy, ret;
+ unsigned int mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = XQueryPointer(_ecore_x_disp, win, &rwin, &cwin,
+ &rx, &ry, &wx, &wy, &mask);
+ if (!ret)
+ wx = wy = -1;
+
+ if (x) *x = wx;
+ if (y) *y = wy;
+}
+
+/**
+ * Retrieve the Visual ID from a given Visual.
+ *
+ * @param visual The Visual to get the ID for.
+ *
+ * @return The visual id.
+ * @since 1.1.0
+ */
+EAPI unsigned int
+ecore_x_visual_id_get(Ecore_X_Visual visual)
+{
+ return XVisualIDFromVisual(visual);
+}
+
+/**
+ * Retrieve the default Visual.
+ *
+ * @param disp The Display to get the Default Visual from
+ * @param screen The Screen.
+ *
+ * @return The default visual.
+ * @since 1.1.0
+ */
+EAPI Ecore_X_Visual
+ecore_x_default_visual_get(Ecore_X_Display *disp,
+ Ecore_X_Screen *screen)
+{
+ return DefaultVisual(disp, ecore_x_screen_index_get(screen));
+}
+
+/**
+ * Retrieve the default Colormap.
+ *
+ * @param disp The Display to get the Default Colormap from
+ * @param screen The Screen.
+ *
+ * @return The default colormap.
+ * @since 1.1.0
+ */
+EAPI Ecore_X_Colormap
+ecore_x_default_colormap_get(Ecore_X_Display *disp,
+ Ecore_X_Screen *screen)
+{
+ return DefaultColormap(disp, ecore_x_screen_index_get(screen));
+}
+
+/**
+ * Retrieve the default depth.
+ *
+ * @param disp The Display to get the Default Depth from
+ * @param screen The Screen.
+ *
+ * @return The default depth.
+ * @since 1.1.0
+ */
+EAPI int
+ecore_x_default_depth_get(Ecore_X_Display *disp,
+ Ecore_X_Screen *screen)
+{
+ return DefaultDepth(disp, ecore_x_screen_index_get(screen));
+}
+
+EAPI void
+ecore_x_xkb_select_group(int group)
+{
+#ifdef ECORE_XKB
+ XkbLockGroup(_ecore_x_disp, XkbUseCoreKbd, group);
+#endif
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+static int
+_ecore_x_event_modifier(unsigned int state)
+{
+ int xmodifiers = 0;
+
+ if (state & ECORE_EVENT_MODIFIER_SHIFT)
+ xmodifiers |= ECORE_X_MODIFIER_SHIFT;
+
+ if (state & ECORE_EVENT_MODIFIER_CTRL)
+ xmodifiers |= ECORE_X_MODIFIER_CTRL;
+
+ if (state & ECORE_EVENT_MODIFIER_ALT)
+ xmodifiers |= ECORE_X_MODIFIER_ALT;
+
+ if (state & ECORE_EVENT_MODIFIER_WIN)
+ xmodifiers |= ECORE_X_MODIFIER_WIN;
+
+ if (state & ECORE_EVENT_MODIFIER_ALTGR)
+ xmodifiers |= ECORE_X_MODIFIER_ALTGR;
+
+ if (state & ECORE_EVENT_LOCK_SCROLL)
+ xmodifiers |= ECORE_X_LOCK_SCROLL;
+
+ if (state & ECORE_EVENT_LOCK_NUM)
+ xmodifiers |= ECORE_X_LOCK_NUM;
+
+ if (state & ECORE_EVENT_LOCK_CAPS)
+ xmodifiers |= ECORE_X_LOCK_CAPS;
+
+ if (state & ECORE_EVENT_LOCK_SHIFT)
+ xmodifiers |= ECORE_X_LOCK_SHIFT;
+
+ return xmodifiers;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_atoms.c b/src/lib/ecore_x/xlib/ecore_x_atoms.c
new file mode 100644
index 0000000000..2aec7ce740
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_atoms.c
@@ -0,0 +1,109 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+#include "ecore_x_atoms_decl.h"
+
+void
+_ecore_x_atoms_init(void)
+{
+ Atom *atoms;
+ char **names;
+ int i, num;
+
+ num = sizeof(atom_items) / sizeof(Atom_Item);
+ atoms = alloca(num * sizeof(Atom));
+ names = alloca(num * sizeof(char *));
+ for (i = 0; i < num; i++)
+ names[i] = (char *) atom_items[i].name;
+ XInternAtoms(_ecore_x_disp, names, num, False, atoms);
+ for (i = 0; i < num; i++)
+ *(atom_items[i].atom) = atoms[i];
+}
+
+/**
+ * Retrieves the atom value associated with the given name.
+ * @param name The given name.
+ * @return Associated atom value.
+ */
+EAPI Ecore_X_Atom
+ecore_x_atom_get(const char *name)
+{
+ if (!_ecore_x_disp)
+ return 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XInternAtom(_ecore_x_disp, name, False);
+}
+
+EAPI void
+ecore_x_atoms_get(const char **names,
+ int num,
+ Ecore_X_Atom *atoms)
+{
+ Atom *atoms_int;
+ int i;
+
+ if (!_ecore_x_disp)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atoms_int = alloca(num * sizeof(Atom));
+ XInternAtoms(_ecore_x_disp, (char **)names, num, False, atoms_int);
+ for (i = 0; i < num; i++)
+ atoms[i] = atoms_int[i];
+}
+
+EAPI char *
+ecore_x_atom_name_get(Ecore_X_Atom atom)
+{
+ char *name;
+ char *xname;
+
+ if (!_ecore_x_disp)
+ return NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xname = XGetAtomName(_ecore_x_disp, atom);
+ if (!xname)
+ return NULL;
+
+ name = strdup(xname);
+ XFree(xname);
+
+ return name;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_composite.c b/src/lib/ecore_x/xlib/ecore_x_composite.c
new file mode 100644
index 0000000000..b919db96d2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_composite.c
@@ -0,0 +1,176 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+static Eina_Bool _composite_available = EINA_FALSE;
+
+void
+_ecore_x_composite_init(void)
+{
+ _composite_available = EINA_FALSE;
+
+#ifdef ECORE_XCOMPOSITE
+ int major, minor;
+
+ if (XCompositeQueryVersion(_ecore_x_disp, &major, &minor))
+ {
+# ifdef ECORE_XRENDER
+ if (XRenderQueryExtension(_ecore_x_disp, &major, &minor))
+ {
+# ifdef ECORE_XFIXES
+ if (XFixesQueryVersion(_ecore_x_disp, &major, &minor))
+ {
+ _composite_available = EINA_TRUE;
+ }
+# endif
+ }
+# endif
+ }
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_composite_query(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _composite_available;
+}
+
+EAPI void
+ecore_x_composite_redirect_window(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+#ifdef ECORE_XCOMPOSITE
+ int update = CompositeRedirectAutomatic;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = CompositeRedirectAutomatic;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = CompositeRedirectManual;
+ break;
+ }
+ XCompositeRedirectWindow(_ecore_x_disp, win, update);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI void
+ecore_x_composite_redirect_subwindows(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+#ifdef ECORE_XCOMPOSITE
+ int update = CompositeRedirectAutomatic;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = CompositeRedirectAutomatic;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = CompositeRedirectManual;
+ break;
+ }
+ XCompositeRedirectSubwindows(_ecore_x_disp, win, update);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI void
+ecore_x_composite_unredirect_window(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+#ifdef ECORE_XCOMPOSITE
+ int update = CompositeRedirectAutomatic;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = CompositeRedirectAutomatic;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = CompositeRedirectManual;
+ break;
+ }
+ XCompositeUnredirectWindow(_ecore_x_disp, win, update);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI void
+ecore_x_composite_unredirect_subwindows(Ecore_X_Window win,
+ Ecore_X_Composite_Update_Type type)
+{
+#ifdef ECORE_XCOMPOSITE
+ int update = CompositeRedirectAutomatic;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ switch (type)
+ {
+ case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC:
+ update = CompositeRedirectAutomatic;
+ break;
+
+ case ECORE_X_COMPOSITE_UPDATE_MANUAL:
+ update = CompositeRedirectManual;
+ break;
+ }
+ XCompositeUnredirectSubwindows(_ecore_x_disp, win, update);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI Ecore_X_Pixmap
+ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win)
+{
+ Ecore_X_Pixmap pixmap = None;
+#ifdef ECORE_XCOMPOSITE
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ pixmap = XCompositeNameWindowPixmap(_ecore_x_disp, win);
+#endif /* ifdef ECORE_XCOMPOSITE */
+ return pixmap;
+}
+
+EAPI void
+ecore_x_composite_window_events_disable(Ecore_X_Window win)
+{
+#ifdef ECORE_XCOMPOSITE
+ ecore_x_window_shape_input_rectangle_set(win, -1, -1, 1, 1);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI void
+ecore_x_composite_window_events_enable(Ecore_X_Window win)
+{
+#ifdef ECORE_XCOMPOSITE
+ ecore_x_window_shape_input_rectangle_set(win, 0, 0, 65535, 65535);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
+EAPI Ecore_X_Window
+ecore_x_composite_render_window_enable(Ecore_X_Window root)
+{
+ Ecore_X_Window win = 0;
+#ifdef ECORE_XCOMPOSITE
+ win = XCompositeGetOverlayWindow(_ecore_x_disp, root);
+ ecore_x_composite_window_events_disable(win);
+#endif /* ifdef ECORE_XCOMPOSITE */
+ return win;
+}
+
+EAPI void
+ecore_x_composite_render_window_disable(Ecore_X_Window root)
+{
+#ifdef ECORE_XCOMPOSITE
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XCompositeReleaseOverlayWindow(_ecore_x_disp, root);
+#endif /* ifdef ECORE_XCOMPOSITE */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_cursor.c b/src/lib/ecore_x/xlib/ecore_x_cursor.c
new file mode 100644
index 0000000000..a968c56af2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_cursor.c
@@ -0,0 +1,246 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include "ecore_x_private.h"
+
+EAPI Eina_Bool
+ecore_x_cursor_color_supported_get(void)
+{
+ return _ecore_x_xcursor;
+}
+
+EAPI Ecore_X_Cursor
+ecore_x_cursor_new(Ecore_X_Window win,
+ int *pixels,
+ int w,
+ int h,
+ int hot_x,
+ int hot_y)
+{
+#ifdef ECORE_XCURSOR
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (_ecore_x_xcursor)
+ {
+ Cursor c;
+ XcursorImage *xci;
+
+ xci = XcursorImageCreate(w, h);
+ if (xci)
+ {
+ int i;
+
+ xci->xhot = hot_x;
+ xci->yhot = hot_y;
+ xci->delay = 0;
+ for (i = 0; i < (w * h); i++)
+ {
+// int r, g, b, a;
+//
+// a = (pixels[i] >> 24) & 0xff;
+// r = (((pixels[i] >> 16) & 0xff) * a) / 0xff;
+// g = (((pixels[i] >> 8 ) & 0xff) * a) / 0xff;
+// b = (((pixels[i] ) & 0xff) * a) / 0xff;
+ xci->pixels[i] = pixels[i];
+// (a << 24) | (r << 16) | (g << 8) | (b);
+ }
+ c = XcursorImageLoadCursor(_ecore_x_disp, xci);
+ XcursorImageDestroy(xci);
+ return c;
+ }
+ }
+ else
+#endif /* ifdef ECORE_XCURSOR */
+ {
+ XColor c1, c2;
+ Cursor c;
+ Pixmap pmap, mask;
+ GC gc;
+ XGCValues gcv;
+ XImage *xim;
+ unsigned int *pix;
+ int fr, fg, fb, br, bg, bb;
+ int brightest = 0;
+ int darkest = 255 * 3;
+ int x, y;
+ const int dither[2][2] =
+ {
+ {0, 2},
+ {3, 1}
+ };
+
+ pmap = XCreatePixmap(_ecore_x_disp, win, w, h, 1);
+ mask = XCreatePixmap(_ecore_x_disp, win, w, h, 1);
+ xim = XCreateImage(_ecore_x_disp,
+ DefaultVisual(_ecore_x_disp, 0),
+ 1, ZPixmap, 0, NULL, w, h, 32, 0);
+ xim->data = malloc(xim->bytes_per_line * xim->height);
+
+ fr = 0x00; fg = 0x00; fb = 0x00;
+ br = 0xff; bg = 0xff; bb = 0xff;
+ pix = (unsigned int *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int r, g, b, a;
+
+ a = (pix[0] >> 24) & 0xff;
+ r = (pix[0] >> 16) & 0xff;
+ g = (pix[0] >> 8) & 0xff;
+ b = (pix[0]) & 0xff;
+ if (a > 0)
+ {
+ if ((r + g + b) > brightest)
+ {
+ brightest = r + g + b;
+ br = r;
+ bg = g;
+ bb = b;
+ }
+
+ if ((r + g + b) < darkest)
+ {
+ darkest = r + g + b;
+ fr = r;
+ fg = g;
+ fb = b;
+ }
+ }
+
+ pix++;
+ }
+ }
+
+ pix = (unsigned int *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int v;
+ int r, g, b;
+ int d1, d2;
+
+ r = (pix[0] >> 16) & 0xff;
+ g = (pix[0] >> 8) & 0xff;
+ b = (pix[0]) & 0xff;
+ d1 =
+ ((r - fr) * (r - fr)) +
+ ((g - fg) * (g - fg)) +
+ ((b - fb) * (b - fb));
+ d2 =
+ ((r - br) * (r - br)) +
+ ((g - bg) * (g - bg)) +
+ ((b - bb) * (b - bb));
+ if (d1 + d2)
+ {
+ v = (((d2 * 255) / (d1 + d2)) * 5) / 256;
+ if (v > dither[x & 0x1][y & 0x1])
+ v = 1;
+ else
+ v = 0;
+ }
+ else
+ v = 0;
+
+ XPutPixel(xim, x, y, v);
+ pix++;
+ }
+ }
+ gc = XCreateGC(_ecore_x_disp, pmap, 0, &gcv);
+ XPutImage(_ecore_x_disp, pmap, gc, xim, 0, 0, 0, 0, w, h);
+ XFreeGC(_ecore_x_disp, gc);
+
+ pix = (unsigned int *)pixels;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int v;
+
+ v = (((pix[0] >> 24) & 0xff) * 5) / 256;
+ if (v > dither[x & 0x1][y & 0x1])
+ v = 1;
+ else
+ v = 0;
+
+ XPutPixel(xim, x, y, v);
+ pix++;
+ }
+ }
+ gc = XCreateGC(_ecore_x_disp, mask, 0, &gcv);
+ XPutImage(_ecore_x_disp, mask, gc, xim, 0, 0, 0, 0, w, h);
+ XFreeGC(_ecore_x_disp, gc);
+
+ free(xim->data);
+ xim->data = NULL;
+ XDestroyImage(xim);
+
+ c1.pixel = 0;
+ c1.red = fr << 8 | fr;
+ c1.green = fg << 8 | fg;
+ c1.blue = fb << 8 | fb;
+ c1.flags = DoRed | DoGreen | DoBlue;
+
+ c2.pixel = 0;
+ c2.red = br << 8 | br;
+ c2.green = bg << 8 | bg;
+ c2.blue = bb << 8 | bb;
+ c2.flags = DoRed | DoGreen | DoBlue;
+
+ c = XCreatePixmapCursor(_ecore_x_disp,
+ pmap, mask,
+ &c1, &c2,
+ hot_x, hot_y);
+ XFreePixmap(_ecore_x_disp, pmap);
+ XFreePixmap(_ecore_x_disp, mask);
+ return c;
+ }
+
+ return 0;
+}
+
+EAPI void
+ecore_x_cursor_free(Ecore_X_Cursor c)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFreeCursor(_ecore_x_disp, c);
+}
+
+/*
+ * Returns the cursor for the given shape.
+ * Note that the return value must not be freed with
+ * ecore_x_cursor_free()!
+ */
+EAPI Ecore_X_Cursor
+ecore_x_cursor_shape_get(int shape)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* Shapes are defined in Ecore_X_Cursor.h */
+ return XCreateFontCursor(_ecore_x_disp, shape);
+}
+
+EAPI void
+ecore_x_cursor_size_set(int size)
+{
+#ifdef ECORE_XCURSOR
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XcursorSetDefaultSize(_ecore_x_disp, size);
+#else /* ifdef ECORE_XCURSOR */
+ size = 0;
+#endif /* ifdef ECORE_XCURSOR */
+}
+
+EAPI int
+ecore_x_cursor_size_get(void)
+{
+#ifdef ECORE_XCURSOR
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XcursorGetDefaultSize(_ecore_x_disp);
+#else /* ifdef ECORE_XCURSOR */
+ return 0;
+#endif /* ifdef ECORE_XCURSOR */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_damage.c b/src/lib/ecore_x/xlib/ecore_x_damage.c
new file mode 100644
index 0000000000..b094f85235
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_damage.c
@@ -0,0 +1,71 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+static Eina_Bool _damage_available = EINA_FALSE;
+#ifdef ECORE_XDAMAGE
+static int _damage_major, _damage_minor;
+#endif /* ifdef ECORE_XDAMAGE */
+
+void
+_ecore_x_damage_init(void)
+{
+#ifdef ECORE_XDAMAGE
+ _damage_major = 1;
+ _damage_minor = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XDamageQueryVersion(_ecore_x_disp, &_damage_major, &_damage_minor))
+ _damage_available = EINA_TRUE;
+ else
+ _damage_available = EINA_FALSE;
+
+#else /* ifdef ECORE_XDAMAGE */
+ _damage_available = EINA_FALSE;
+#endif /* ifdef ECORE_XDAMAGE */
+}
+
+EAPI Eina_Bool
+ecore_x_damage_query(void)
+{
+ return _damage_available;
+}
+
+EAPI Ecore_X_Damage
+ecore_x_damage_new(Ecore_X_Drawable d,
+ Ecore_X_Damage_Report_Level level)
+{
+#ifdef ECORE_XDAMAGE
+ Ecore_X_Damage damage;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ damage = XDamageCreate(_ecore_x_disp, d, level);
+ return damage;
+#else /* ifdef ECORE_XDAMAGE */
+ return 0;
+#endif /* ifdef ECORE_XDAMAGE */
+}
+
+EAPI void
+ecore_x_damage_free(Ecore_X_Damage damage)
+{
+#ifdef ECORE_XDAMAGE
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XDamageDestroy(_ecore_x_disp, damage);
+#endif /* ifdef ECORE_XDAMAGE */
+}
+
+EAPI void
+ecore_x_damage_subtract(Ecore_X_Damage damage,
+ Ecore_X_Region repair,
+ Ecore_X_Region parts)
+{
+#ifdef ECORE_XDAMAGE
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XDamageSubtract(_ecore_x_disp, damage, repair, parts);
+#endif /* ifdef ECORE_XDAMAGE */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_dnd.c b/src/lib/ecore_x/xlib/ecore_x_dnd.c
new file mode 100644
index 0000000000..e4f74a7257
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_dnd.c
@@ -0,0 +1,706 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+EAPI int ECORE_X_EVENT_XDND_ENTER = 0;
+EAPI int ECORE_X_EVENT_XDND_POSITION = 0;
+EAPI int ECORE_X_EVENT_XDND_STATUS = 0;
+EAPI int ECORE_X_EVENT_XDND_LEAVE = 0;
+EAPI int ECORE_X_EVENT_XDND_DROP = 0;
+EAPI int ECORE_X_EVENT_XDND_FINISHED = 0;
+
+static Ecore_X_DND_Source *_source = NULL;
+static Ecore_X_DND_Target *_target = NULL;
+static int _ecore_x_dnd_init_count = 0;
+
+typedef struct _Version_Cache_Item
+{
+ Ecore_X_Window win;
+ int ver;
+} Version_Cache_Item;
+static Version_Cache_Item *_version_cache = NULL;
+static int _version_cache_num = 0, _version_cache_alloc = 0;
+static void (*_posupdatecb)(void *,
+ Ecore_X_Xdnd_Position *);
+static void *_posupdatedata;
+
+void
+_ecore_x_dnd_init(void)
+{
+ if (!_ecore_x_dnd_init_count)
+ {
+ _source = calloc(1, sizeof(Ecore_X_DND_Source));
+ if (!_source) return;
+ _source->version = ECORE_X_DND_VERSION;
+ _source->win = None;
+ _source->dest = None;
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ _source->prev.window = 0;
+
+ _target = calloc(1, sizeof(Ecore_X_DND_Target));
+ if (!_target)
+ {
+ free(_source);
+ _source = NULL;
+ return;
+ }
+ _target->win = None;
+ _target->source = None;
+ _target->state = ECORE_X_DND_TARGET_IDLE;
+
+ ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_DROP = ecore_event_type_new();
+ ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new();
+ }
+
+ _ecore_x_dnd_init_count++;
+}
+
+void
+_ecore_x_dnd_shutdown(void)
+{
+ _ecore_x_dnd_init_count--;
+ if (_ecore_x_dnd_init_count > 0)
+ return;
+
+ if (_source)
+ free(_source);
+
+ _source = NULL;
+
+ if (_target)
+ free(_target);
+
+ _target = NULL;
+
+ _ecore_x_dnd_init_count = 0;
+}
+
+static Eina_Bool
+_ecore_x_dnd_converter_copy(char *target EINA_UNUSED,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *tprop EINA_UNUSED,
+ int *count EINA_UNUSED)
+{
+ XTextProperty text_prop;
+ char *mystr;
+ XICCEncodingStyle style = XTextStyle;
+
+ if (!data || !size)
+ return EINA_FALSE;
+
+ mystr = calloc(1, size + 1);
+ if (!mystr)
+ return EINA_FALSE;
+
+ memcpy(mystr, data, size);
+
+ if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
+ &text_prop) == Success)
+ {
+ int bufsize = strlen((char *)text_prop.value) + 1;
+ *data_ret = malloc(bufsize);
+ if (!*data_ret)
+ {
+ free(mystr);
+ return EINA_FALSE;
+ }
+ memcpy(*data_ret, text_prop.value, bufsize);
+ *size_ret = bufsize;
+ XFree(text_prop.value);
+ free(mystr);
+ return EINA_TRUE;
+ }
+ else
+ {
+ free(mystr);
+ return EINA_FALSE;
+ }
+}
+
+EAPI void
+ecore_x_dnd_aware_set(Ecore_X_Window win,
+ Eina_Bool on)
+{
+ Ecore_X_Atom prop_data = ECORE_X_DND_VERSION;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (on)
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE,
+ XA_ATOM, 32, &prop_data, 1);
+ else
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE);
+}
+
+EAPI int
+ecore_x_dnd_version_get(Ecore_X_Window win)
+{
+ unsigned char *prop_data;
+ int num;
+ Version_Cache_Item *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ // this looks hacky - and it is, but we need a way of caching info about
+ // a window while dragging, because we literally query this every mouse
+ // move and going to and from x multiple times per move is EXPENSIVE
+ // and slows things down, puts lots of load on x etc.
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ if (_version_cache)
+ {
+ int i;
+
+ for (i = 0; i < _version_cache_num; i++)
+ {
+ if (_version_cache[i].win == win)
+ return _version_cache[i].ver;
+ }
+ }
+
+ if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE,
+ XA_ATOM, 32, &prop_data, &num))
+ {
+ int version = (int)*prop_data;
+ free(prop_data);
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ {
+ _version_cache_num++;
+ if (_version_cache_num > _version_cache_alloc)
+ _version_cache_alloc += 16;
+
+ t = realloc(_version_cache,
+ _version_cache_alloc *
+ sizeof(Version_Cache_Item));
+ if (!t) return 0;
+ _version_cache = t;
+ _version_cache[_version_cache_num - 1].win = win;
+ _version_cache[_version_cache_num - 1].ver = version;
+ }
+
+ return version;
+ }
+
+ if (_source->state == ECORE_X_DND_SOURCE_DRAGGING)
+ {
+ _version_cache_num++;
+ if (_version_cache_num > _version_cache_alloc)
+ _version_cache_alloc += 16;
+
+ t = realloc(_version_cache, _version_cache_alloc *
+ sizeof(Version_Cache_Item));
+ if (!t) return 0;
+ _version_cache = t;
+ _version_cache[_version_cache_num - 1].win = win;
+ _version_cache[_version_cache_num - 1].ver = 0;
+ }
+
+ return 0;
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_type_isset(Ecore_X_Window win,
+ const char *type)
+{
+ int num, i, ret = EINA_FALSE;
+ unsigned char *data;
+ Ecore_X_Atom *atoms, atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM, 32, &data, &num))
+ return ret;
+
+ atom = ecore_x_atom_get(type);
+ atoms = (Ecore_X_Atom *)data;
+
+ for (i = 0; i < num; ++i)
+ {
+ if (atom == atoms[i])
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+ XFree(data);
+ return ret;
+}
+
+EAPI void
+ecore_x_dnd_type_set(Ecore_X_Window win,
+ const char *type,
+ Eina_Bool on)
+{
+ Ecore_X_Atom atom;
+ Ecore_X_Atom *oldset = NULL, *newset = NULL;
+ int i, j = 0, num = 0;
+ unsigned char *data = NULL;
+ unsigned char *old_data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = ecore_x_atom_get(type);
+ ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM, 32, &old_data, &num);
+ oldset = (Ecore_X_Atom *)old_data;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (on)
+ {
+ if (ecore_x_dnd_type_isset(win, type))
+ {
+ XFree(old_data);
+ return;
+ }
+
+ newset = calloc(num + 1, sizeof(Ecore_X_Atom));
+ if (!newset)
+ return;
+
+ data = (unsigned char *)newset;
+
+ for (i = 0; i < num; i++)
+ newset[i + 1] = oldset[i];
+ /* prepend the new type */
+ newset[0] = atom;
+
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM, 32, data, num + 1);
+ }
+ else
+ {
+ if (!ecore_x_dnd_type_isset(win, type))
+ {
+ XFree(old_data);
+ return;
+ }
+
+ newset = calloc(num - 1, sizeof(Ecore_X_Atom));
+ if (!newset)
+ {
+ XFree(old_data);
+ return;
+ }
+
+ data = (unsigned char *)newset;
+ for (i = 0; i < num; i++)
+ if (oldset[i] != atom)
+ newset[j++] = oldset[i];
+
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM, 32, data, num - 1);
+ }
+
+ XFree(oldset);
+ free(newset);
+}
+
+EAPI void
+ecore_x_dnd_types_set(Ecore_X_Window win,
+ const char **types,
+ unsigned int num_types)
+{
+ Ecore_X_Atom *newset = NULL;
+ unsigned int i;
+ unsigned char *data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!num_types)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST);
+ else
+ {
+ newset = calloc(num_types, sizeof(Ecore_X_Atom));
+ if (!newset)
+ return;
+
+ data = (unsigned char *)newset;
+ for (i = 0; i < num_types; i++)
+ {
+ newset[i] = ecore_x_atom_get(types[i]);
+ ecore_x_selection_converter_atom_add(newset[i],
+ _ecore_x_dnd_converter_copy);
+ }
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM, 32, data, num_types);
+ free(newset);
+ }
+}
+
+EAPI void
+ecore_x_dnd_actions_set(Ecore_X_Window win,
+ Ecore_X_Atom *actions,
+ unsigned int num_actions)
+{
+ unsigned int i;
+ unsigned char *data = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!num_actions)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST);
+ else
+ {
+ data = (unsigned char *)actions;
+ for (i = 0; i < num_actions; i++)
+ {
+ ecore_x_selection_converter_atom_add(actions[i],
+ _ecore_x_dnd_converter_copy);
+ }
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST,
+ XA_ATOM, 32, data, num_actions);
+ }
+}
+
+/**
+ * The DND position update cb is called Ecore_X sends a DND position to a
+ * client.
+ *
+ * It essentially mirrors some of the data sent in the position message.
+ * Generally this cb should be set just before position update is called.
+ * Please note well you need to look after your own data pointer if someone
+ * trashes you position update cb set.
+ *
+ * It is considered good form to clear this when the dnd event finishes.
+ *
+ * @param cb Callback to updated each time ecore_x sends a position update.
+ * @param data User data.
+ */
+EAPI void
+ecore_x_dnd_callback_pos_update_set(
+ void (*cb)(void *,
+ Ecore_X_Xdnd_Position *data),
+ const void *data)
+{
+ _posupdatecb = cb;
+ _posupdatedata = (void *)data; /* Discard the const early */
+}
+
+Ecore_X_DND_Source *
+_ecore_x_dnd_source_get(void)
+{
+ return _source;
+}
+
+Ecore_X_DND_Target *
+_ecore_x_dnd_target_get(void)
+{
+ return _target;
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_begin(Ecore_X_Window source,
+ unsigned char *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_dnd_version_get(source))
+ return EINA_FALSE;
+
+ /* Take ownership of XdndSelection */
+ if (!ecore_x_selection_xdnd_set(source, data, size))
+ return EINA_FALSE;
+
+ if (_version_cache)
+ {
+ free(_version_cache);
+ _version_cache = NULL;
+ _version_cache_num = 0;
+ _version_cache_alloc = 0;
+ }
+
+ ecore_x_window_shadow_tree_flush();
+
+ _source->win = source;
+ ecore_x_window_ignore_set(_source->win, 1);
+ _source->state = ECORE_X_DND_SOURCE_DRAGGING;
+ _source->time = _ecore_x_event_last_time;
+ _source->prev.window = 0;
+
+ /* Default Accepted Action: move */
+ _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
+ _source->accepted_action = None;
+ _source->dest = None;
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_dnd_drop(void)
+{
+ XEvent xev;
+ int status = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (_source->dest)
+ {
+ xev.xany.type = ClientMessage;
+ xev.xany.display = _ecore_x_disp;
+ xev.xclient.format = 32;
+ xev.xclient.window = _source->dest;
+
+ if (_source->will_accept)
+ {
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_DROP;
+ xev.xclient.data.l[0] = _source->win;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = _source->time;
+ XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
+ _source->state = ECORE_X_DND_SOURCE_DROPPED;
+ status = EINA_TRUE;
+ }
+ else
+ {
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE;
+ xev.xclient.data.l[0] = _source->win;
+ xev.xclient.data.l[1] = 0;
+ XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+ }
+ else
+ {
+ /* Dropping on nothing */
+ ecore_x_selection_xdnd_clear();
+ _source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+
+ ecore_x_window_ignore_set(_source->win, 0);
+
+ _source->prev.window = 0;
+
+ return status;
+}
+
+EAPI void
+ecore_x_dnd_send_status(Eina_Bool will_accept,
+ Eina_Bool suppress,
+ Ecore_X_Rectangle rectangle,
+ Ecore_X_Atom action)
+{
+ XEvent xev;
+
+ if (_target->state == ECORE_X_DND_TARGET_IDLE)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ memset(&xev, 0, sizeof(XEvent));
+
+ _target->will_accept = will_accept;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_STATUS;
+ xev.xclient.format = 32;
+ xev.xclient.window = _target->source;
+
+ xev.xclient.data.l[0] = _target->win;
+ xev.xclient.data.l[1] = 0;
+ if (will_accept)
+ xev.xclient.data.l[1] |= 0x1UL;
+
+ if (!suppress)
+ xev.xclient.data.l[1] |= 0x2UL;
+
+ /* Set rectangle information */
+ xev.xclient.data.l[2] = rectangle.x;
+ xev.xclient.data.l[2] <<= 16;
+ xev.xclient.data.l[2] |= rectangle.y;
+ xev.xclient.data.l[3] = rectangle.width;
+ xev.xclient.data.l[3] <<= 16;
+ xev.xclient.data.l[3] |= rectangle.height;
+
+ if (will_accept)
+ {
+ xev.xclient.data.l[4] = action;
+ _target->accepted_action = action;
+ }
+ else
+ {
+ xev.xclient.data.l[4] = None;
+ _target->accepted_action = action;
+ }
+
+ XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev);
+}
+
+EAPI void
+ecore_x_dnd_send_finished(void)
+{
+ XEvent xev;
+
+ if (_target->state == ECORE_X_DND_TARGET_IDLE)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xany.type = ClientMessage;
+ xev.xany.display = _ecore_x_disp;
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_FINISHED;
+ xev.xclient.format = 32;
+ xev.xclient.window = _target->source;
+
+ xev.xclient.data.l[0] = _target->win;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+ if (_target->will_accept)
+ {
+ xev.xclient.data.l[1] |= 0x1UL;
+ xev.xclient.data.l[2] = _target->accepted_action;
+ }
+
+ XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev);
+
+ _target->state = ECORE_X_DND_TARGET_IDLE;
+}
+
+EAPI void
+ecore_x_dnd_source_action_set(Ecore_X_Atom action)
+{
+ _source->action = action;
+ if (_source->prev.window)
+ _ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y);
+}
+
+EAPI Ecore_X_Atom
+ecore_x_dnd_source_action_get(void)
+{
+ return _source->action;
+}
+
+void
+_ecore_x_dnd_drag(Ecore_X_Window root,
+ int x,
+ int y)
+{
+ XEvent xev;
+ Ecore_X_Window win;
+ Ecore_X_Window *skip;
+ Ecore_X_Xdnd_Position pos;
+ int num;
+
+ if (_source->state != ECORE_X_DND_SOURCE_DRAGGING)
+ return;
+
+ /* Preinitialize XEvent struct */
+ memset(&xev, 0, sizeof(XEvent));
+ xev.xany.type = ClientMessage;
+ xev.xany.display = _ecore_x_disp;
+ xev.xclient.format = 32;
+
+ /* Attempt to find a DND-capable window under the cursor */
+ skip = ecore_x_window_ignore_list(&num);
+// WARNING - this function is HEAVY. it goes to and from x a LOT walking the
+// window tree - use the SHADOW version - makes a 1-off tree copy, then uses
+// that instead.
+// win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num);
+ win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num);
+
+// NOTE: This now uses the shadow version to find parent windows
+// while ((win) && !(ecore_x_dnd_version_get(win)))
+// win = ecore_x_window_parent_get(win);
+ while ((win) && !(ecore_x_dnd_version_get(win)))
+ win = ecore_x_window_shadow_parent_get(root, win);
+
+ /* Send XdndLeave to current destination window if we have left it */
+ if ((_source->dest) && (win != _source->dest))
+ {
+ xev.xclient.window = _source->dest;
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE;
+ xev.xclient.data.l[0] = _source->win;
+ xev.xclient.data.l[1] = 0;
+
+ XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev);
+ _source->suppress = 0;
+ }
+
+ if (win)
+ {
+ int x1, x2, y1, y2;
+
+ _source->version = MIN(ECORE_X_DND_VERSION,
+ ecore_x_dnd_version_get(win));
+ if (win != _source->dest)
+ {
+ int i;
+ unsigned char *data;
+ Ecore_X_Atom *types;
+
+ ecore_x_window_prop_property_get(_source->win,
+ ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM,
+ 32,
+ &data,
+ &num);
+ types = (Ecore_X_Atom *)data;
+
+ /* Entered new window, send XdndEnter */
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_ENTER;
+ xev.xclient.data.l[0] = _source->win;
+ xev.xclient.data.l[1] = 0;
+ if (num > 3)
+ xev.xclient.data.l[1] |= 0x1UL;
+ else
+ xev.xclient.data.l[1] &= 0xfffffffeUL;
+
+ xev.xclient.data.l[1] |= ((unsigned long)_source->version) << 24;
+
+ for (i = 2; i < 5; i++)
+ xev.xclient.data.l[i] = 0;
+ for (i = 0; i < MIN(num, 3); ++i)
+ xev.xclient.data.l[i + 2] = types[i];
+ XFree(data);
+ XSendEvent(_ecore_x_disp, win, False, 0, &xev);
+ _source->await_status = 0;
+ _source->will_accept = 0;
+ }
+
+ /* Determine if we're still in the rectangle from the last status */
+ x1 = _source->rectangle.x;
+ x2 = _source->rectangle.x + _source->rectangle.width;
+ y1 = _source->rectangle.y;
+ y2 = _source->rectangle.y + _source->rectangle.height;
+
+ if ((!_source->await_status) ||
+ (!_source->suppress) ||
+ ((x < x1) || (x > x2) || (y < y1) || (y > y2)))
+ {
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_XDND_POSITION;
+ xev.xclient.data.l[0] = _source->win;
+ xev.xclient.data.l[1] = 0; /* Reserved */
+ xev.xclient.data.l[2] = ((x << 16) & 0xffff0000) | (y & 0xffff);
+ xev.xclient.data.l[3] = _source->time; /* Version 1 */
+ xev.xclient.data.l[4] = _source->action; /* Version 2, Needs to be pre-set */
+ XSendEvent(_ecore_x_disp, win, False, 0, &xev);
+
+ _source->await_status = 1;
+ }
+ }
+
+ if (_posupdatecb)
+ {
+ pos.position.x = x;
+ pos.position.y = y;
+ pos.win = win;
+ pos.prev = _source->dest;
+ _posupdatecb(_posupdatedata, &pos);
+ }
+
+ _source->prev.x = x;
+ _source->prev.y = y;
+ _source->prev.window = root;
+ _source->dest = win;
+}
+
+/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
diff --git a/src/lib/ecore_x/xlib/ecore_x_dpms.c b/src/lib/ecore_x/xlib/ecore_x_dpms.c
new file mode 100644
index 0000000000..23349f44e6
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_dpms.c
@@ -0,0 +1,247 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+
+static Eina_Bool _dpms_available = EINA_FALSE;
+
+void
+_ecore_x_dpms_init(void)
+{
+#ifdef ECORE_XDPMS
+ int _dpms_major, _dpms_minor;
+
+ _dpms_major = 1;
+ _dpms_minor = 0;
+
+ if (DPMSGetVersion(_ecore_x_disp, &_dpms_major, &_dpms_minor))
+ _dpms_available = EINA_TRUE;
+ else
+ _dpms_available = EINA_FALSE;
+
+#else /* ifdef ECORE_XDPMS */
+ _dpms_available = EINA_FALSE;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions
+ *
+ * Functions related to the X DPMS extension.
+ */
+
+/**
+ * Checks if the X DPMS extension is available on the server.
+ * @return @c 1 if the X DPMS extension is available, @c 0 otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_query(void)
+{
+ return _dpms_available;
+}
+
+/**
+ * Checks if the X server is capable of DPMS.
+ * @return @c 1 if the X server is capable of DPMS, @c 0 otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_capable_get(void)
+{
+#ifdef ECORE_XDPMS
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return DPMSCapable(_ecore_x_disp) ? EINA_TRUE : EINA_FALSE;
+#else /* ifdef ECORE_XDPMS */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Checks the DPMS state of the display.
+ * @return @c 1 if DPMS is enabled, @c 0 otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_enabled_get(void)
+{
+#ifdef ECORE_XDPMS
+ unsigned char state;
+ unsigned short power_lvl;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSInfo(_ecore_x_disp, &power_lvl, &state);
+ return state ? EINA_TRUE : EINA_FALSE;
+#else /* ifdef ECORE_XDPMS */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Sets the DPMS state of the display.
+ * @param enabled @c 0 to disable DPMS characteristics of the server, enable it otherwise.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_enabled_set(int enabled)
+{
+#ifdef ECORE_XDPMS
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (enabled)
+ DPMSEnable(_ecore_x_disp);
+ else
+ DPMSDisable(_ecore_x_disp);
+
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Gets the timeouts. The values are in unit of seconds.
+ * @param standby Amount of time of inactivity before standby mode will be invoked.
+ * @param suspend Amount of time of inactivity before the screen is placed into suspend mode.
+ * @param off Amount of time of inactivity before the monitor is shut off.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeouts_get(unsigned int *standby,
+ unsigned int *suspend,
+ unsigned int *off)
+{
+#ifdef ECORE_XDPMS
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, (unsigned short *)standby,
+ (unsigned short *)suspend, (unsigned short *)off);
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Sets the timeouts. The values are in unit of seconds.
+ * @param standby Amount of time of inactivity before standby mode will be invoked.
+ * @param suspend Amount of time of inactivity before the screen is placed into suspend mode.
+ * @param off Amount of time of inactivity before the monitor is shut off.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI Eina_Bool
+ecore_x_dpms_timeouts_set(unsigned int standby,
+ unsigned int suspend,
+ unsigned int off)
+{
+#ifdef ECORE_XDPMS
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return DPMSSetTimeouts(_ecore_x_disp, standby, suspend, off) ? EINA_TRUE : EINA_FALSE;
+#else /* ifdef ECORE_XDPMS */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Returns the amount of time of inactivity before standby mode is invoked.
+ * @return The standby timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_standby_get(void)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ return standby;
+#else /* ifdef ECORE_XDPMS */
+ return 0;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Returns the amount of time of inactivity before the second level of
+ * power saving is invoked.
+ * @return The suspend timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_suspend_get(void)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ return suspend;
+#else /* ifdef ECORE_XDPMS */
+ return 0;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Returns the amount of time of inactivity before the third and final
+ * level of power saving is invoked.
+ * @return The off timeout value.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI unsigned int
+ecore_x_dpms_timeout_off_get(void)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ return off;
+#else /* ifdef ECORE_XDPMS */
+ return 0;
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Sets the standby timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before standby mode will be invoked.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_standby_set(unsigned int new_timeout)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ DPMSSetTimeouts(_ecore_x_disp, new_timeout, suspend, off);
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Sets the suspend timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before the screen is placed into suspend mode.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ DPMSSetTimeouts(_ecore_x_disp, standby, new_timeout, off);
+#endif /* ifdef ECORE_XDPMS */
+}
+
+/**
+ * Sets the off timeout (in unit of seconds).
+ * @param new_timeout Amount of time of inactivity before the monitor is shut off.
+ * @ingroup Ecore_X_DPMS_Group
+ */
+EAPI void
+ecore_x_dpms_timeout_off_set(unsigned int new_timeout)
+{
+#ifdef ECORE_XDPMS
+ unsigned short standby, suspend, off;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off);
+ DPMSSetTimeouts(_ecore_x_disp, standby, suspend, new_timeout);
+#endif /* ifdef ECORE_XDPMS */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_drawable.c b/src/lib/ecore_x/xlib/ecore_x_drawable.c
new file mode 100644
index 0000000000..d1b41114da
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_drawable.c
@@ -0,0 +1,118 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+
+/**
+ * @defgroup Ecore_X_Drawable_Group X Drawable Functions
+ *
+ * Functions that operate on drawables.
+ */
+
+/**
+ * Retrieves the geometry of the given drawable.
+ * @param d The given drawable.
+ * @param x Pointer to an integer into which the X position is to be stored.
+ * @param y Pointer to an integer into which the Y position is to be stored.
+ * @param w Pointer to an integer into which the width is to be stored.
+ * @param h Pointer to an integer into which the height is to be stored.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI void
+ecore_x_drawable_geometry_get(Ecore_X_Drawable d,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ Window dummy_win;
+ int ret_x, ret_y;
+ unsigned int ret_w, ret_h, dummy_border, dummy_depth;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &ret_x, &ret_y,
+ &ret_w, &ret_h, &dummy_border, &dummy_depth))
+ {
+ ret_x = 0;
+ ret_y = 0;
+ ret_w = 0;
+ ret_h = 0;
+ }
+
+ if (x)
+ *x = ret_x;
+
+ if (y)
+ *y = ret_y;
+
+ if (w)
+ *w = (int)ret_w;
+
+ if (h)
+ *h = (int)ret_h;
+}
+
+/**
+ * Retrieves the width of the border of the given drawable.
+ * @param d The given drawable.
+ * @return The border width of the given drawable.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI int
+ecore_x_drawable_border_width_get(Ecore_X_Drawable d)
+{
+ Window dummy_win;
+ int dummy_x, dummy_y;
+ unsigned int dummy_w, dummy_h, border_ret, dummy_depth;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &dummy_x, &dummy_y,
+ &dummy_w, &dummy_h, &border_ret, &dummy_depth))
+ border_ret = 0;
+
+ return (int)border_ret;
+}
+
+/**
+ * Retrieves the depth of the given drawable.
+ * @param d The given drawable.
+ * @return The depth of the given drawable.
+ * @ingroup Ecore_X_Drawable_Group
+ */
+EAPI int
+ecore_x_drawable_depth_get(Ecore_X_Drawable d)
+{
+ Window dummy_win;
+ int dummy_x, dummy_y;
+ unsigned int dummy_w, dummy_h, dummy_border, depth_ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &dummy_x, &dummy_y,
+ &dummy_w, &dummy_h, &dummy_border, &depth_ret))
+ depth_ret = 0;
+
+ return (int)depth_ret;
+}
+
+/**
+ * Fill the specified rectangle on a drawable.
+ * @param d The given drawable.
+ * @param gc The graphic context that controls the fill rules.
+ * @param x The X coordinate of the top-left corner of the rectangle.
+ * @param y The Y coordinate of the top-left corner of the rectangle.
+ * @param width The width of the rectangle.
+ * @param height The height of the rectangle.
+ */
+EAPI void
+ecore_x_drawable_rectangle_fill(Ecore_X_Drawable d,
+ Ecore_X_GC gc,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFillRectangle(_ecore_x_disp, d, gc, x, y, width, height);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_e.c b/src/lib/ecore_x/xlib/ecore_x_e.c
new file mode 100644
index 0000000000..430b24b117
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_e.c
@@ -0,0 +1,1670 @@
+/*
+ * OLD E hints
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+EAPI void
+ecore_x_e_init(void)
+{
+}
+
+EAPI void
+ecore_x_e_frame_size_set(Ecore_X_Window win,
+ int fl,
+ int fr,
+ int ft,
+ int fb)
+{
+ unsigned int frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ frames[0] = fl;
+ frames[1] = fr;
+ frames[2] = ft;
+ frames[3] = fb;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_FRAME_SIZE, frames, 4);
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_set(Ecore_X_Window win,
+ unsigned int is_keyboard)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD,
+ &is_keyboard, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_virtual_keyboard_get(Ecore_X_Window win)
+{
+ unsigned int val;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+static Ecore_X_Virtual_Keyboard_State
+_ecore_x_e_vkbd_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_ON;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_IP;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_URL;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD;
+
+ if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME)
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME;
+
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_x_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_ON:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_IP:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_URL:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD;
+
+ case ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME:
+ return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME;
+
+ default: break;
+ }
+ return 0;
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win,
+ Ecore_X_Virtual_Keyboard_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_vkbd_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Virtual_Keyboard_State
+ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ &atom, 1))
+ return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN;
+
+ return _ecore_x_e_vkbd_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win,
+ Ecore_X_Virtual_Keyboard_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_vkbd_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_illume_atom_get(Ecore_X_Illume_Mode mode)
+{
+ switch (mode)
+ {
+ case ECORE_X_ILLUME_MODE_SINGLE:
+ return ECORE_X_ATOM_E_ILLUME_MODE_SINGLE;
+
+ case ECORE_X_ILLUME_MODE_DUAL_TOP:
+ return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP;
+
+ case ECORE_X_ILLUME_MODE_DUAL_LEFT:
+ return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT;
+
+ default:
+ break;
+ }
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+}
+
+static Ecore_X_Illume_Mode
+_ecore_x_e_illume_mode_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_SINGLE)
+ return ECORE_X_ILLUME_MODE_SINGLE;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP)
+ return ECORE_X_ILLUME_MODE_DUAL_TOP;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT)
+ return ECORE_X_ILLUME_MODE_DUAL_LEFT;
+
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_zone_set(Ecore_X_Window win,
+ Ecore_X_Window zone)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE,
+ &zone, 1);
+}
+
+EAPI Ecore_X_Window
+ecore_x_e_illume_zone_get(Ecore_X_Window win)
+{
+ Ecore_X_Window zone;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_window_get(win, ECORE_X_ATOM_E_ILLUME_ZONE,
+ &zone, 1))
+ return 0;
+
+ return zone;
+}
+
+EAPI void
+ecore_x_e_illume_zone_list_set(Ecore_X_Window win,
+ Ecore_X_Window *zones,
+ unsigned int n_zones)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE_LIST,
+ zones, n_zones);
+}
+
+EAPI void
+ecore_x_e_illume_conformant_set(Ecore_X_Window win,
+ unsigned int is_conformant)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT,
+ &is_conformant, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_conformant_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_mode_set(Ecore_X_Window win,
+ Ecore_X_Illume_Mode mode)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_illume_atom_get(mode);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_MODE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Mode
+ecore_x_e_illume_mode_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1))
+ return ECORE_X_ILLUME_MODE_UNKNOWN;
+
+ return _ecore_x_e_illume_mode_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_mode_send(Ecore_X_Window win,
+ Ecore_X_Illume_Mode mode)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_MODE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_illume_atom_get(mode),
+ 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_back_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_BACK,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_forward_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_focus_home_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_HOME,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_close_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_CLOSE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_home_new_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_NEW,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_home_del_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_DEL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_next_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_up_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_access_action_down_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ win,
+ ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN,
+ 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_drag_set(Ecore_X_Window win,
+ unsigned int drag)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG, &drag, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_drag_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG, &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_drag_locked_set(Ecore_X_Window win,
+ unsigned int is_locked)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED,
+ &is_locked, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_drag_locked_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_drag_start_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_START,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_drag_end_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_END,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY,
+ geom, 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (x)
+ *x = geom[0];
+
+ if (y)
+ *y = geom[1];
+
+ if (w)
+ *w = geom[2];
+
+ if (h)
+ *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY,
+ geom, 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (x)
+ *x = geom[0];
+
+ if (y)
+ *y = geom[1];
+
+ if (w)
+ *w = geom[2];
+
+ if (h)
+ *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY,
+ geom, 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (x)
+ *x = geom[0];
+
+ if (y)
+ *y = geom[1];
+
+ if (w)
+ *w = geom[2];
+
+ if (h)
+ *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+static Ecore_X_Atom
+_ecore_x_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_QUICKPANEL_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON;
+
+ case ECORE_X_ILLUME_QUICKPANEL_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Quickpanel_State
+_ecore_x_e_quickpanel_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON)
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_ON;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF)
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_OFF;
+
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_set(Ecore_X_Window win,
+ unsigned int is_quickpanel)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL,
+ &is_quickpanel, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_quickpanel_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL,
+ &val, 1))
+ return EINA_FALSE;
+
+ return val ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Quickpanel_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_quickpanel_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Quickpanel_State
+ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN;
+
+ return _ecore_x_e_quickpanel_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win,
+ Ecore_X_Illume_Quickpanel_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_quickpanel_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 0, 0, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win,
+ unsigned int priority)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR,
+ &priority, 1);
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win,
+ unsigned int priority)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR,
+ &priority, 1);
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win,
+ unsigned int zone)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE,
+ &zone, 1);
+}
+
+EAPI int
+ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win)
+{
+ unsigned int val = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE,
+ &val, 1))
+ return 0;
+
+ return val;
+}
+
+EAPI void
+ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ 1, 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_clipboard_atom_get(Ecore_X_Illume_Clipboard_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_CLIPBOARD_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON;
+ case ECORE_X_ILLUME_CLIPBOARD_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Clipboard_State
+_ecore_x_e_clipboard_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON)
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_ON;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF)
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_OFF;
+
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Clipboard_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_clipboard_atom_get(state);
+
+ ecore_x_window_prop_atom_set(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Clipboard_State
+ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN;
+ return _ecore_x_e_clipboard_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win,
+ int x, int y, int w, int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY,
+ geom, 4);
+}
+
+EAPI Eina_Bool
+ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win,
+ int *x, int *y, int *w, int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY,
+ geom, 4);
+ if (ret != 4) return EINA_FALSE;
+
+ if (x) *x = geom[0];
+ if (y) *y = geom[1];
+ if (w) *w = geom[2];
+ if (h) *h = geom[3];
+
+ return EINA_TRUE;
+}
+
+/* for sliding window */
+EAPI void
+ecore_x_e_illume_sliding_win_state_set(Ecore_X_Window win,
+ unsigned int is_visible)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE,
+ &is_visible, 1);
+} /* ecore_x_e_illume_sliding_win_state_set */
+
+EAPI int
+ecore_x_e_illume_sliding_win_state_get(Ecore_X_Window win)
+{
+ unsigned int is_visible = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE,
+ &is_visible, 1))
+ return 0;
+
+ return is_visible;
+}
+
+EAPI void
+ecore_x_e_illume_sliding_win_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geom[0] = x;
+ geom[1] = y;
+ geom[2] = w;
+ geom[3] = h;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY,
+ geom, 4);
+} /* ecore_x_e_illume_sliding_win_geometry_set */
+
+EAPI int
+ecore_x_e_illume_sliding_win_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ int ret = 0;
+ unsigned int geom[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY,
+ geom, 4);
+ if (ret != 4)
+ return 0;
+
+ if (x)
+ *x = geom[0];
+
+ if (y)
+ *y = geom[1];
+
+ if (w)
+ *w = geom[2];
+
+ if (h)
+ *h = geom[3];
+
+ return 1;
+}/* ecore_x_e_illume_sliding_win_geometry_get */
+
+EAPI void
+ecore_x_e_comp_sync_counter_set(Ecore_X_Window win,
+ Ecore_X_Sync_Counter counter)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (counter)
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER,
+ ECORE_X_ATOM_CARDINAL, &counter, 1);
+ else
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER);
+}
+
+EAPI Ecore_X_Sync_Counter
+ecore_x_e_comp_sync_counter_get(Ecore_X_Window win)
+{
+ int ret = 0;
+ Ecore_X_Sync_Counter counter = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_xid_get(win,
+ ECORE_X_ATOM_E_COMP_SYNC_COUNTER,
+ ECORE_X_ATOM_CARDINAL,
+ &counter, 1);
+ if (ret != 1)
+ return 0;
+
+ return counter;
+}
+
+EAPI void
+ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root,
+ Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // version
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root,
+ Ecore_X_Window win,
+ int w,
+ int h)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 1; // version
+ xev.xclient.data.l[2] = w; // win width at draw time
+ xev.xclient.data.l[3] = h; // win height at draw time
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+/*
+ * @since 1.3
+ *
+ */
+EAPI void
+ecore_x_e_window_profile_list_set(Ecore_X_Window win,
+ const char **profiles,
+ unsigned int num_profiles)
+{
+ Ecore_X_Atom *atoms;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ return;
+
+ if (!num_profiles)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE_LIST);
+ else
+ {
+ atoms = alloca(num_profiles * sizeof(Ecore_X_Atom));
+ ecore_x_atoms_get(profiles, num_profiles, atoms);
+ ecore_x_window_prop_property_set(win,
+ ECORE_X_ATOM_E_PROFILE_LIST,
+ XA_ATOM, 32, (void *)atoms,
+ num_profiles);
+ }
+}
+
+/*
+ * @since 1.3
+ */
+EAPI Eina_Bool
+ecore_x_e_window_profile_list_get(Ecore_X_Window win,
+ const char ***profiles,
+ int *ret_num)
+{
+ unsigned char *data;
+ Ecore_X_Atom *atoms;
+ int num, i;
+
+ if (ret_num)
+ *ret_num = 0;
+
+ if (profiles)
+ *profiles = NULL;
+
+ if (!win)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win,
+ ECORE_X_ATOM_E_PROFILE_LIST,
+ XA_ATOM, 32, &data, &num))
+ return EINA_FALSE;
+
+ if (ret_num)
+ *ret_num = num;
+
+ if (profiles)
+ {
+ (*profiles) = calloc(num, sizeof(char *));
+ if (!(*profiles))
+ {
+ if (ret_num)
+ *ret_num = 0;
+
+ if (data)
+ free(data);
+
+ return EINA_FALSE;
+ }
+
+ atoms = (Ecore_X_Atom *)data;
+ for (i = 0; i < num; i++)
+ (*profiles)[i] = ecore_x_atom_name_get(atoms[i]);
+ }
+
+ if (data)
+ XFree(data);
+
+ return EINA_TRUE;
+}
+
+/*
+ * @since 1.3
+ */
+EAPI void
+ecore_x_e_window_profile_set(Ecore_X_Window win,
+ const char *profile)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ return;
+
+ if (!profile)
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE);
+ else
+ {
+ atom = ecore_x_atom_get(profile);
+ ecore_x_window_prop_property_set(win, ECORE_X_ATOM_E_PROFILE,
+ XA_ATOM, 32, (void *)&atom, 1);
+ }
+}
+
+/*
+ * @since 1.3
+ */
+EAPI char *
+ecore_x_e_window_profile_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom *atom = NULL;
+ unsigned char *data;
+ char *profile = NULL;
+ int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_E_PROFILE,
+ XA_ATOM, 32, &data, &num))
+ return NULL;
+
+ if (data)
+ atom = (Ecore_X_Atom *)data;
+
+ if (atom)
+ profile = ecore_x_atom_name_get(atom[0]);
+
+ return profile;
+}
+
+EAPI void
+ecore_x_e_comp_sync_supported_set(Ecore_X_Window root,
+ Eina_Bool enabled)
+{
+ Ecore_X_Window win;
+
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (enabled)
+ {
+ win = ecore_x_window_new(root, 1, 2, 3, 4);
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ ecore_x_window_prop_xid_set(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW, &win, 1);
+ }
+ else
+ {
+ int ret;
+
+ ret =
+ ecore_x_window_prop_xid_get(root,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW,
+ &win, 1);
+ if ((ret == 1) && (win))
+ {
+ ecore_x_window_prop_property_del(
+ root,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED);
+ ecore_x_window_free(win);
+ }
+ }
+}
+
+EAPI Eina_Bool
+ecore_x_e_comp_sync_supported_get(Ecore_X_Window root)
+{
+ Ecore_X_Window win, win2;
+ int ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ ret =
+ ecore_x_window_prop_xid_get(root,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW,
+ &win, 1);
+ if ((ret == 1) && (win))
+ {
+ ret =
+ ecore_x_window_prop_xid_get(win,
+ ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED,
+ ECORE_X_ATOM_WINDOW,
+ &win2, 1);
+ if ((ret == 1) && (win2 == win))
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_e_comp_sync_begin_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_BEGIN;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // later
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, win, False,
+ NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_sync_end_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_END;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // later
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, win, False,
+ NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_CANCEL;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // later
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, win, False,
+ NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_flush_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_FLUSH;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // later
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, win, False,
+ NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_dump_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_E_COMP_DUMP;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = win;
+ xev.xclient.data.l[1] = 0; // later
+ xev.xclient.data.l[2] = 0; // later
+ xev.xclient.data.l[3] = 0; // later
+ xev.xclient.data.l[4] = 0; // later
+
+ XSendEvent(_ecore_x_disp, win, False,
+ NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
+
+EAPI void
+ecore_x_e_comp_pixmap_set(Ecore_X_Window win,
+ Ecore_X_Pixmap pixmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (pixmap)
+ ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_PIXMAP,
+ ECORE_X_ATOM_PIXMAP, &pixmap, 1);
+ else
+ ecore_x_window_prop_property_del(win, pixmap);
+}
+
+EAPI Ecore_X_Pixmap
+ecore_x_e_comp_pixmap_get(Ecore_X_Window win)
+{
+ int ret = 0;
+ Ecore_X_Pixmap pixmap = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret =
+ ecore_x_window_prop_xid_get(win,
+ ECORE_X_ATOM_E_COMP_PIXMAP,
+ ECORE_X_ATOM_PIXMAP,
+ &pixmap, 1);
+ if (ret != 1)
+ return 0;
+
+ return pixmap;
+}
+
+static Ecore_X_Atom
+_ecore_x_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_INDICATOR_STATE_ON:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_ON;
+
+ case ECORE_X_ILLUME_INDICATOR_STATE_OFF:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Indicator_State
+_ecore_x_e_indicator_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_ON)
+ return ECORE_X_ILLUME_INDICATOR_STATE_ON;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF)
+ return ECORE_X_ILLUME_INDICATOR_STATE_OFF;
+
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_indicator_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_indicator_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Indicator_State
+ecore_x_e_illume_indicator_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN;
+
+ return _ecore_x_e_indicator_state_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_indicator_state_send(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_State state)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_indicator_atom_get(state),
+ 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_indicator_opacity_atom_get(Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ switch (mode)
+ {
+ case ECORE_X_ILLUME_INDICATOR_OPAQUE:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE;
+
+ case ECORE_X_ILLUME_INDICATOR_TRANSLUCENT:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT;
+
+ case ECORE_X_ILLUME_INDICATOR_TRANSPARENT:
+ return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Indicator_Opacity_Mode
+_ecore_x_e_indicator_opacity_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE)
+ return ECORE_X_ILLUME_INDICATOR_OPAQUE;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT)
+ return ECORE_X_ILLUME_INDICATOR_TRANSLUCENT;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT)
+ return ECORE_X_ILLUME_INDICATOR_TRANSPARENT;
+
+ return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN;
+}
+
+EAPI void
+ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_indicator_opacity_atom_get(mode);
+ ecore_x_window_prop_atom_set(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Indicator_Opacity_Mode
+ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ &atom, 1))
+ return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN;
+
+ return _ecore_x_e_indicator_opacity_get(atom);
+}
+
+EAPI void
+ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win,
+ Ecore_X_Illume_Indicator_Opacity_Mode mode)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win,
+ ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE,
+ ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
+ _ecore_x_e_indicator_opacity_atom_get(mode),
+ 0, 0, 0, 0);
+}
+
+static Ecore_X_Atom
+_ecore_x_e_illume_window_state_atom_get(Ecore_X_Illume_Window_State state)
+{
+ switch (state)
+ {
+ case ECORE_X_ILLUME_WINDOW_STATE_NORMAL:
+ return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL;
+
+ case ECORE_X_ILLUME_WINDOW_STATE_FLOATING:
+ return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static Ecore_X_Illume_Window_State
+_ecore_x_e_illume_window_state_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL)
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+
+ if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING)
+ return ECORE_X_ILLUME_WINDOW_STATE_FLOATING;
+
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+}
+
+EAPI void
+ecore_x_e_illume_window_state_set(Ecore_X_Window win,
+ Ecore_X_Illume_Window_State state)
+{
+ Ecore_X_Atom atom = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_e_illume_window_state_atom_get(state);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_WINDOW_STATE,
+ &atom, 1);
+}
+
+EAPI Ecore_X_Illume_Window_State
+ecore_x_e_illume_window_state_get(Ecore_X_Window win)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_atom_get(win,
+ ECORE_X_ATOM_E_ILLUME_WINDOW_STATE,
+ &atom, 1))
+ return ECORE_X_ILLUME_WINDOW_STATE_NORMAL;
+
+ return _ecore_x_e_illume_window_state_get(atom);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_error.c b/src/lib/ecore_x/xlib/ecore_x_error.c
new file mode 100644
index 0000000000..f6eb075b54
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_error.c
@@ -0,0 +1,126 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+static int _ecore_x_error_handle(Display *d,
+ XErrorEvent *ev);
+static int _ecore_x_io_error_handle(Display *d);
+
+static void (*_error_func)(void *data) = NULL;
+static void *_error_data = NULL;
+static void (*_io_error_func)(void *data) = NULL;
+static void *_io_error_data = NULL;
+static int _error_request_code = 0;
+static int _error_code = 0;
+static Ecore_X_ID _error_resource_id = 0;
+
+/**
+ * Set the error handler.
+ * @param func The error handler function
+ * @param data The data to be passed to the handler function
+ *
+ * Set the X error handler function
+ */
+EAPI void
+ecore_x_error_handler_set(void (*func)(void *data),
+ const void *data)
+{
+ _error_func = func;
+ _error_data = (void *)data;
+}
+
+/**
+ * Set the I/O error handler.
+ * @param func The I/O error handler function
+ * @param data The data to be passed to the handler function
+ *
+ * Set the X I/O error handler function
+ */
+EAPI void
+ecore_x_io_error_handler_set(void (*func)(void *data),
+ const void *data)
+{
+ _io_error_func = func;
+ _io_error_data = (void *)data;
+}
+
+/**
+ * Get the request code that caused the error.
+ * @return The request code causing the X error
+ *
+ * Return the X request code that caused the last X error
+ */
+EAPI int
+ecore_x_error_request_get(void)
+{
+ return _error_request_code;
+}
+
+/**
+ * Get the error code from the error.
+ * @return The error code from the X error
+ *
+ * Return the error code from the last X error
+ */
+//FIXME: Use Ecore_X_Error_Code type when 2.0 is released
+EAPI int
+ecore_x_error_code_get(void)
+{
+ return _error_code;
+}
+
+/**
+ * Get the resource id that caused the error.
+ * @return The resource id causing the X error
+ *
+ * Return the X resource id that caused the last X error
+ */
+EAPI Ecore_X_ID
+ecore_x_error_resource_id_get(void)
+{
+ return _error_resource_id;
+}
+
+void
+_ecore_x_error_handler_init(void)
+{
+ XSetErrorHandler((XErrorHandler)_ecore_x_error_handle);
+ XSetIOErrorHandler((XIOErrorHandler)_ecore_x_io_error_handle);
+}
+
+static int
+_ecore_x_error_handle(Display *d,
+ XErrorEvent *ev)
+{
+ if (d == _ecore_x_disp)
+ {
+ _error_request_code = ev->request_code;
+ _error_code = ev->error_code;
+ _error_resource_id = ev->resourceid;
+ if (_error_func)
+ _error_func(_error_data);
+ }
+ return 0;
+}
+
+static int
+_ecore_x_io_error_handle(Display *d)
+{
+ if (d == _ecore_x_disp)
+ {
+ if (_io_error_func)
+ _io_error_func(_io_error_data);
+ else
+ exit(-1);
+ }
+
+ return 0;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_events.c b/src/lib/ecore_x/xlib/ecore_x_events.c
new file mode 100644
index 0000000000..9ce7163d53
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_events.c
@@ -0,0 +1,2523 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <langinfo.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+/** OpenBSD does not define CODESET
+ * FIXME ??
+ */
+
+#ifndef CODESET
+#define CODESET "INVALID"
+#endif /* ifndef CODESET */
+
+typedef struct _Ecore_X_Mouse_Down_Info
+{
+ EINA_INLIST;
+ int dev;
+ Window last_win;
+ Window last_last_win;
+ Window last_event_win;
+ Window last_last_event_win;
+ Time last_time;
+ Time last_last_time;
+ Eina_Bool did_double : 1;
+ Eina_Bool did_triple : 1;
+} Ecore_X_Mouse_Down_Info;
+
+static int _ecore_x_last_event_mouse_move = 0;
+static Ecore_Event *_ecore_x_last_event_mouse_move_event = NULL;
+static Eina_Inlist *_ecore_x_mouse_down_info_list = NULL;
+
+static void
+_ecore_x_mouse_down_info_clear(void)
+{
+ Eina_Inlist *l = _ecore_x_mouse_down_info_list;
+ Ecore_X_Mouse_Down_Info *info = NULL;
+ while (l)
+ {
+ info = EINA_INLIST_CONTAINER_GET(l, Ecore_X_Mouse_Down_Info);
+ l = eina_inlist_remove(l, l);
+ free(info);
+ }
+ _ecore_x_mouse_down_info_list = NULL;
+}
+
+void
+_ecore_x_events_init(void)
+{
+ //Actually, Nothing to do.
+}
+
+void
+_ecore_x_events_shutdown(void)
+{
+ _ecore_x_mouse_down_info_clear();
+}
+
+static Ecore_X_Mouse_Down_Info *
+_ecore_x_mouse_down_info_get(int dev)
+{
+ Eina_Inlist *l = _ecore_x_mouse_down_info_list;
+ Ecore_X_Mouse_Down_Info *info = NULL;
+
+ //Return the exist info
+ EINA_INLIST_FOREACH(l, info)
+ if (info->dev == dev) return info;
+
+ //New Device. Add it.
+ info = calloc(1, sizeof(Ecore_X_Mouse_Down_Info));
+ if (!info) return NULL;
+
+ info->dev = dev;
+ l = eina_inlist_append(l, (Eina_Inlist *)info);
+ _ecore_x_mouse_down_info_list = l;
+ return info;
+}
+
+static void
+_ecore_x_event_free_mouse_move(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_Event_Mouse_Move *e;
+
+ e = ev;
+ if (_ecore_x_last_event_mouse_move)
+ {
+ _ecore_x_last_event_mouse_move_event = NULL;
+ _ecore_x_last_event_mouse_move = 0;
+ }
+
+ free(e);
+}
+
+EAPI void
+ecore_x_event_mask_set(Ecore_X_Window w,
+ Ecore_X_Event_Mask mask)
+{
+ XWindowAttributes attr;
+ XSetWindowAttributes s_attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!w)
+ w = DefaultRootWindow(_ecore_x_disp);
+
+ memset(&attr, 0, sizeof(XWindowAttributes));
+ XGetWindowAttributes(_ecore_x_disp, w, &attr);
+ s_attr.event_mask = mask | attr.your_event_mask;
+ XChangeWindowAttributes(_ecore_x_disp, w, CWEventMask, &s_attr);
+}
+
+EAPI void
+ecore_x_event_mask_unset(Ecore_X_Window w,
+ Ecore_X_Event_Mask mask)
+{
+ XWindowAttributes attr;
+ XSetWindowAttributes s_attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!w)
+ w = DefaultRootWindow(_ecore_x_disp);
+
+ memset(&attr, 0, sizeof(XWindowAttributes));
+ XGetWindowAttributes(_ecore_x_disp, w, &attr);
+ s_attr.event_mask = attr.your_event_mask & ~mask;
+ XChangeWindowAttributes(_ecore_x_disp, w, CWEventMask, &s_attr);
+}
+
+static void
+_ecore_x_event_free_xdnd_enter(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_X_Event_Xdnd_Enter *e;
+ int i;
+
+ e = ev;
+ for (i = 0; i < e->num_types; i++)
+ XFree(e->types[i]);
+ free(e->types);
+ free(e);
+}
+
+static void
+_ecore_x_event_free_selection_notify(void *data EINA_UNUSED,
+ void *ev)
+{
+ Ecore_X_Event_Selection_Notify *e;
+ Ecore_X_Selection_Data *sel;
+
+ e = ev;
+ sel = e->data;
+ if (sel->free)
+ sel->free(sel);
+
+ free(e->target);
+ free(e);
+}
+
+static unsigned int
+_ecore_x_event_modifiers(unsigned int state)
+{
+ unsigned int modifiers = 0;
+
+ if (state & ECORE_X_MODIFIER_SHIFT)
+ modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+
+ if (state & ECORE_X_MODIFIER_CTRL)
+ modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+
+ if (state & ECORE_X_MODIFIER_ALT)
+ modifiers |= ECORE_EVENT_MODIFIER_ALT;
+
+ if (state & ECORE_X_MODIFIER_WIN)
+ modifiers |= ECORE_EVENT_MODIFIER_WIN;
+
+ if (state & ECORE_X_MODIFIER_ALTGR)
+ modifiers |= ECORE_EVENT_MODIFIER_ALTGR;
+
+ if (state & ECORE_X_LOCK_SCROLL)
+ modifiers |= ECORE_EVENT_LOCK_SCROLL;
+
+ if (state & ECORE_X_LOCK_NUM)
+ modifiers |= ECORE_EVENT_LOCK_NUM;
+
+ if (state & ECORE_X_LOCK_CAPS)
+ modifiers |= ECORE_EVENT_LOCK_CAPS;
+
+ if (state & ECORE_X_LOCK_SHIFT)
+ modifiers |= ECORE_EVENT_LOCK_SHIFT;
+
+ return modifiers;
+}
+
+void
+_ecore_mouse_move(unsigned int timestamp,
+ unsigned int xmodifiers,
+ int x,
+ int y,
+ int x_root,
+ int y_root,
+ unsigned int event_window,
+ unsigned int window,
+ unsigned int root_win,
+ int same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ double mx,
+ double my,
+ double mrx,
+ double mry)
+{
+ Ecore_Event_Mouse_Move *e;
+ Ecore_Event *event;
+
+ e = malloc(sizeof(Ecore_Event_Mouse_Move));
+ if (!e)
+ return;
+
+ e->window = window;
+ e->root_window = root_win;
+ e->timestamp = timestamp;
+ e->same_screen = same_screen;
+ e->event_window = event_window;
+
+ e->modifiers = _ecore_x_event_modifiers(xmodifiers);
+ e->x = x;
+ e->y = y;
+ e->root.x = x_root;
+ e->root.y = y_root;
+
+ e->multi.device = dev;
+ e->multi.radius = (radx + rady) / 2;
+ e->multi.radius_x = radx;
+ e->multi.radius_y = rady;
+ e->multi.pressure = pressure;
+ e->multi.angle = angle;
+ e->multi.x = mx;
+ e->multi.y = my;
+ e->multi.root.x = mrx;
+ e->multi.root.y = mry;
+
+ event = ecore_event_add(ECORE_EVENT_MOUSE_MOVE,
+ e,
+ _ecore_x_event_free_mouse_move,
+ NULL);
+
+ _ecore_x_event_last_time = timestamp;
+ _ecore_x_event_last_win = window;
+ _ecore_x_event_last_root_x = x_root;
+ _ecore_x_event_last_root_y = y_root;
+
+ _ecore_x_last_event_mouse_move_event = event;
+}
+
+static void
+_ecore_key_press(int event,
+ XKeyEvent *xevent)
+{
+ Ecore_Event_Key *e;
+ char *compose = NULL;
+ char *tmp = NULL;
+ char *keyname;
+ char *key;
+ char keyname_buffer[256];
+ char compose_buffer[256];
+ KeySym sym;
+ XComposeStatus status;
+ int val;
+
+ _ecore_x_last_event_mouse_move = 0;
+ keyname = XKeysymToString(_ecore_x_XKeycodeToKeysym(xevent->display,
+ xevent->keycode, 0));
+ if (!keyname)
+ {
+ snprintf(keyname_buffer,
+ sizeof(keyname_buffer),
+ "Keycode-%i",
+ xevent->keycode);
+ keyname = keyname_buffer;
+ }
+
+ sym = 0;
+ key = NULL;
+ compose = NULL;
+ val = XLookupString(xevent,
+ compose_buffer,
+ sizeof(compose_buffer),
+ &sym,
+ &status);
+ if (val > 0)
+ {
+ compose_buffer[val] = 0;
+ compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8",
+ compose_buffer);
+ if (!compose)
+ ERR("Ecore_X cannot convert input key string '%s' to UTF-8. "
+ "Is Eina built with iconv support?", compose_buffer);
+ tmp = compose;
+ }
+
+ key = XKeysymToString(sym);
+ if (!key)
+ key = keyname;
+
+ e =
+ malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
+ (compose ? strlen(compose) : 0) + 3);
+ if (!e)
+ goto on_error;
+
+ e->keyname = (char *)(e + 1);
+ e->key = e->keyname + strlen(keyname) + 1;
+ e->compose = (compose) ? e->key + strlen(key) + 1 : NULL;
+ e->string = e->compose;
+
+ strcpy((char *)e->keyname, keyname);
+ strcpy((char *)e->key, key);
+ if (compose)
+ strcpy((char *)e->compose, compose);
+
+ e->modifiers = _ecore_x_event_modifiers(xevent->state);
+
+ e->timestamp = xevent->time;
+ e->window = xevent->subwindow ? xevent->subwindow : xevent->window;
+ e->event_window = xevent->window;
+ e->same_screen = xevent->same_screen;
+ e->root_window = xevent->root;
+
+ ecore_event_add(event, e, NULL, NULL);
+
+ _ecore_x_event_last_time = e->timestamp;
+
+on_error:
+ if (tmp)
+ free(tmp);
+}
+
+Ecore_Event_Mouse_Button *
+_ecore_mouse_button(int event,
+ unsigned int timestamp,
+ unsigned int xmodifiers,
+ unsigned int buttons,
+ int x,
+ int y,
+ int x_root,
+ int y_root,
+ unsigned int event_window,
+ unsigned int window,
+ unsigned int root_win,
+ int same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ double mx,
+ double my,
+ double mrx,
+ double mry)
+{
+ Ecore_Event_Mouse_Button *e;
+
+ e = malloc(sizeof(Ecore_Event_Mouse_Button));
+ if (!e)
+ return NULL;
+
+ e->window = window;
+ e->root_window = root_win;
+ e->timestamp = timestamp;
+ e->same_screen = same_screen;
+ e->event_window = event_window;
+
+ e->buttons = buttons;
+ e->modifiers = _ecore_x_event_modifiers(xmodifiers);
+ e->double_click = 0;
+ e->triple_click = 0;
+ e->x = x;
+ e->y = y;
+ e->root.x = x_root;
+ e->root.y = y_root;
+
+ Ecore_X_Mouse_Down_Info *down_info = _ecore_x_mouse_down_info_get(dev);
+
+ if (down_info)
+ {
+ if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) &&
+ down_info->did_triple)
+ {
+ down_info->last_win = 0;
+ down_info->last_last_win = 0;
+ down_info->last_event_win = 0;
+ down_info->last_last_event_win = 0;
+ down_info->last_time = 0;
+ down_info->last_last_time = 0;
+ }
+ if (event_window == window)
+ {
+ if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN)
+ {
+ //Check Double Clicked
+ if (((int)(timestamp - down_info->last_time) <=
+ (int)(1000 * _ecore_x_double_click_time)) &&
+ (window == down_info->last_win) &&
+ (event_window == down_info->last_event_win))
+ {
+ e->double_click = 1;
+ down_info->did_double = EINA_TRUE;
+ }
+ else
+ {
+ down_info->did_double = EINA_FALSE;
+ down_info->did_triple = EINA_FALSE;
+ }
+
+ //Check Triple Clicked
+ if (((int)(timestamp - down_info->last_last_time) <=
+ (int)(2 * 1000 * _ecore_x_double_click_time)) &&
+ (window == down_info->last_win) &&
+ (window == down_info->last_last_win) &&
+ (event_window == down_info->last_event_win) &&
+ (event_window == down_info->last_last_event_win)
+ )
+ {
+ e->triple_click = 1;
+ down_info->did_triple = EINA_TRUE;
+ }
+ else
+ {
+ down_info->did_triple = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (down_info->did_double)
+ e->double_click = 1;
+ if (down_info->did_triple)
+ e->triple_click = 1;
+ }
+ }
+ }
+
+ /* NB: Block commented out as _ecore_x_mouse_up_count appears to have
+ * no use. The variable is also commented out above. This code block is
+ * the only place that this variable is used, and appears to serve no
+ * purpose. - dh
+ if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN
+ && !e->double_click
+ && !e->triple_click)
+ _ecore_x_mouse_up_count = 0;
+ */
+
+ e->multi.device = dev;
+ e->multi.radius = (radx + rady) / 2;
+ e->multi.radius_x = radx;
+ e->multi.radius_y = rady;
+ e->multi.pressure = pressure;
+ e->multi.angle = angle;
+ e->multi.x = mx;
+ e->multi.y = my;
+ e->multi.root.x = mrx;
+ e->multi.root.y = mry;
+
+ _ecore_x_event_last_time = e->timestamp;
+ _ecore_x_event_last_win = e->window;
+ _ecore_x_event_last_root_x = x_root;
+ _ecore_x_event_last_root_y = y_root;
+
+ ecore_event_add(event, e, NULL, NULL);
+
+ if ((down_info) &&
+ (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) &&
+ (window == event_window) &&
+ (!down_info->did_triple))
+ {
+ down_info->last_last_win = down_info->last_win;
+ down_info->last_win = window;
+ down_info->last_last_event_win = down_info->last_event_win;
+ down_info->last_event_win = event_window;
+ down_info->last_last_time = down_info->last_time;
+ down_info->last_time = timestamp;
+ }
+
+ return e;
+}
+
+void
+_ecore_x_event_handle_any_event(XEvent *xevent)
+{
+ XEvent *ev = malloc(sizeof(XEvent));
+ if (!ev) return;
+ memcpy(ev, xevent, sizeof(XEvent));
+ ecore_event_add(ECORE_X_EVENT_ANY, ev, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_key_press(XEvent *xevent)
+{
+ _ecore_key_press(ECORE_EVENT_KEY_DOWN, (XKeyEvent *)xevent);
+}
+
+void
+_ecore_x_event_handle_key_release(XEvent *xevent)
+{
+ _ecore_key_press(ECORE_EVENT_KEY_UP, (XKeyEvent *)xevent);
+}
+
+void
+_ecore_x_event_handle_button_press(XEvent *xevent)
+{
+ int i;
+
+ _ecore_x_last_event_mouse_move = 0;
+ if ((xevent->xbutton.button > 3) && (xevent->xbutton.button < 8))
+ {
+ Ecore_Event_Mouse_Wheel *e;
+
+ e = malloc(sizeof(Ecore_Event_Mouse_Wheel));
+ if (!e)
+ return;
+
+ e->timestamp = xevent->xbutton.time;
+ e->modifiers = _ecore_x_event_modifiers(xevent->xbutton.state);
+ switch (xevent->xbutton.button)
+ {
+ case 4: e->direction = 0; e->z = -1; break;
+
+ case 5: e->direction = 0; e->z = 1; break;
+
+ case 6: e->direction = 1; e->z = -1; break;
+
+ case 7: e->direction = 1; e->z = 1; break;
+
+ default: e->direction = 0; e->z = 0; break;
+ }
+
+ e->x = xevent->xbutton.x;
+ e->y = xevent->xbutton.y;
+ e->root.x = xevent->xbutton.x_root;
+ e->root.y = xevent->xbutton.y_root;
+
+ if (xevent->xbutton.subwindow)
+ e->window = xevent->xbutton.subwindow;
+ else
+ e->window = xevent->xbutton.window;
+
+ e->event_window = xevent->xbutton.window;
+ e->same_screen = xevent->xbutton.same_screen;
+ e->root_window = xevent->xbutton.root;
+
+ _ecore_x_event_last_time = e->timestamp;
+ _ecore_x_event_last_win = e->window;
+ _ecore_x_event_last_root_x = xevent->xbutton.x_root;
+ _ecore_x_event_last_root_y = xevent->xbutton.y_root;
+ ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL);
+
+ for (i = 0; i < _ecore_window_grabs_num; i++)
+ {
+ if ((_ecore_window_grabs[i] == xevent->xbutton.window) ||
+ (_ecore_window_grabs[i] == xevent->xbutton.subwindow))
+ {
+ Eina_Bool replay = EINA_FALSE;
+
+ if (_ecore_window_grab_replay_func)
+ replay = _ecore_window_grab_replay_func(
+ _ecore_window_grab_replay_data,
+ ECORE_EVENT_MOUSE_WHEEL,
+ e);
+
+ if (replay)
+ XAllowEvents(xevent->xbutton.display,
+ ReplayPointer, xevent->xbutton.time);
+ else
+ XAllowEvents(xevent->xbutton.display,
+ AsyncPointer, xevent->xbutton.time);
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ {
+ _ecore_mouse_move(xevent->xbutton.time, xevent->xbutton.state,
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root,
+ xevent->xbutton.window,
+ (xevent->xbutton.subwindow ? xevent->xbutton.
+ subwindow : xevent->xbutton.window),
+ xevent->xbutton.root,
+ xevent->xbutton.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root);
+ }
+ {
+ Ecore_Event_Mouse_Button *e;
+ int event_window;
+ int window;
+
+ window =
+ (xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent->
+ xbutton.window);
+ event_window = xevent->xbutton.window;
+
+ e = _ecore_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ xevent->xbutton.time,
+ xevent->xbutton.state,
+ xevent->xbutton.button,
+ xevent->xbutton.x,
+ xevent->xbutton.y,
+ xevent->xbutton.x_root,
+ xevent->xbutton.y_root,
+ event_window,
+ window,
+ xevent->xbutton.root,
+ xevent->xbutton.same_screen,
+ 0,
+ 1,
+ 1,
+ 1.0,
+// pressure
+ 0.0,
+// angle
+ xevent->xbutton.x,
+ xevent->xbutton.y,
+ xevent->xbutton.x_root,
+ xevent->xbutton.y_root);
+ if (e)
+ for (i = 0; i < _ecore_window_grabs_num; i++)
+ {
+ if ((_ecore_window_grabs[i] == xevent->xbutton.window) ||
+ (_ecore_window_grabs[i] == xevent->xbutton.subwindow))
+ {
+ Eina_Bool replay = EINA_FALSE;
+
+ if (_ecore_window_grab_replay_func)
+ replay = _ecore_window_grab_replay_func(
+ _ecore_window_grab_replay_data,
+ ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ e);
+
+ if (replay)
+ XAllowEvents(xevent->xbutton.display,
+ ReplayPointer, xevent->xbutton.time);
+ else
+ XAllowEvents(xevent->xbutton.display,
+ AsyncPointer, xevent->xbutton.time);
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+void
+_ecore_x_event_handle_button_release(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ /* filter out wheel buttons */
+ if ((xevent->xbutton.button <= 3) || (xevent->xbutton.button > 7))
+ {
+ _ecore_mouse_move(xevent->xbutton.time, xevent->xbutton.state,
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root,
+ xevent->xbutton.window,
+ (xevent->xbutton.subwindow ? xevent->xbutton.
+ subwindow : xevent->xbutton.window),
+ xevent->xbutton.root,
+ xevent->xbutton.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root);
+
+ _ecore_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP,
+ xevent->xbutton.time, xevent->xbutton.state,
+ xevent->xbutton.button,
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root,
+ xevent->xbutton.window,
+ (xevent->xbutton.subwindow ? xevent->xbutton.
+ subwindow : xevent->xbutton.window),
+ xevent->xbutton.root,
+ xevent->xbutton.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xbutton.x, xevent->xbutton.y,
+ xevent->xbutton.x_root, xevent->xbutton.y_root);
+ }
+}
+
+void
+_ecore_x_event_handle_motion_notify(XEvent *xevent)
+{
+/*
+ if (_ecore_x_last_event_mouse_move)
+ {
+ ecore_event_del(_ecore_x_last_event_mouse_move_event);
+ _ecore_x_last_event_mouse_move = 0;
+ _ecore_x_last_event_mouse_move_event = NULL;
+ }
+ */
+ _ecore_mouse_move(xevent->xmotion.time, xevent->xmotion.state,
+ xevent->xmotion.x, xevent->xmotion.y,
+ xevent->xmotion.x_root, xevent->xmotion.y_root,
+ xevent->xmotion.window,
+ (xevent->xmotion.subwindow ? xevent->xmotion.subwindow :
+ xevent->xmotion.window),
+ xevent->xmotion.root,
+ xevent->xmotion.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xmotion.x, xevent->xmotion.y,
+ xevent->xmotion.x_root, xevent->xmotion.y_root);
+
+ _ecore_x_last_event_mouse_move = 1;
+
+ /* Xdnd handling */
+ _ecore_x_dnd_drag(xevent->xmotion.root,
+ xevent->xmotion.x_root,
+ xevent->xmotion.y_root);
+}
+
+void
+_ecore_x_event_handle_enter_notify(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ {
+ _ecore_mouse_move(xevent->xcrossing.time, xevent->xcrossing.state,
+ xevent->xcrossing.x, xevent->xcrossing.y,
+ xevent->xcrossing.x_root, xevent->xcrossing.y_root,
+ xevent->xcrossing.window,
+ (xevent->xcrossing.subwindow ? xevent->xcrossing.
+ subwindow : xevent->xcrossing.window),
+ xevent->xcrossing.root,
+ xevent->xcrossing.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xcrossing.x, xevent->xcrossing.y,
+ xevent->xcrossing.x_root, xevent->xcrossing.y_root);
+ }
+ {
+ Ecore_X_Event_Mouse_In *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Mouse_In));
+ if (!e)
+ return;
+
+ e->modifiers = _ecore_x_event_modifiers(xevent->xcrossing.state);
+ e->x = xevent->xcrossing.x;
+ e->y = xevent->xcrossing.y;
+ e->root.x = xevent->xcrossing.x_root;
+ e->root.y = xevent->xcrossing.y_root;
+ if (xevent->xcrossing.subwindow)
+ e->win = xevent->xcrossing.subwindow;
+ else
+ e->win = xevent->xcrossing.window;
+
+ e->same_screen = xevent->xcrossing.same_screen;
+ e->root_win = xevent->xcrossing.root;
+ e->event_win = xevent->xcrossing.window;
+
+ if (xevent->xcrossing.mode == NotifyNormal)
+ e->mode = ECORE_X_EVENT_MODE_NORMAL;
+ else if (xevent->xcrossing.mode == NotifyGrab)
+ e->mode = ECORE_X_EVENT_MODE_GRAB;
+ else if (xevent->xcrossing.mode == NotifyUngrab)
+ e->mode = ECORE_X_EVENT_MODE_UNGRAB;
+
+ if (xevent->xcrossing.detail == NotifyAncestor)
+ e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR;
+ else if (xevent->xcrossing.detail == NotifyVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL;
+ else if (xevent->xcrossing.detail == NotifyInferior)
+ e->detail = ECORE_X_EVENT_DETAIL_INFERIOR;
+ else if (xevent->xcrossing.detail == NotifyNonlinear)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR;
+ else if (xevent->xcrossing.detail == NotifyNonlinearVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL;
+
+ e->time = xevent->xcrossing.time;
+ _ecore_x_event_last_time = e->time;
+ ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_x_event_handle_leave_notify(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ {
+ _ecore_mouse_move(xevent->xcrossing.time, xevent->xcrossing.state,
+ xevent->xcrossing.x, xevent->xcrossing.y,
+ xevent->xcrossing.x_root, xevent->xcrossing.y_root,
+ xevent->xcrossing.window,
+ (xevent->xcrossing.subwindow ? xevent->xcrossing.
+ subwindow : xevent->xcrossing.window),
+ xevent->xcrossing.root,
+ xevent->xcrossing.same_screen,
+ 0, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ xevent->xcrossing.x, xevent->xcrossing.y,
+ xevent->xcrossing.x_root, xevent->xcrossing.y_root);
+ }
+ {
+ Ecore_X_Event_Mouse_Out *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out));
+ if (!e)
+ return;
+
+ e->modifiers = _ecore_x_event_modifiers(xevent->xcrossing.state);
+ e->x = xevent->xcrossing.x;
+ e->y = xevent->xcrossing.y;
+ e->root.x = xevent->xcrossing.x_root;
+ e->root.y = xevent->xcrossing.y_root;
+ if (xevent->xcrossing.subwindow)
+ e->win = xevent->xcrossing.subwindow;
+ else
+ e->win = xevent->xcrossing.window;
+
+ e->same_screen = xevent->xcrossing.same_screen;
+ e->root_win = xevent->xcrossing.root;
+ e->event_win = xevent->xcrossing.window;
+
+ if (xevent->xcrossing.mode == NotifyNormal)
+ e->mode = ECORE_X_EVENT_MODE_NORMAL;
+ else if (xevent->xcrossing.mode == NotifyGrab)
+ e->mode = ECORE_X_EVENT_MODE_GRAB;
+ else if (xevent->xcrossing.mode == NotifyUngrab)
+ e->mode = ECORE_X_EVENT_MODE_UNGRAB;
+
+ if (xevent->xcrossing.detail == NotifyAncestor)
+ e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR;
+ else if (xevent->xcrossing.detail == NotifyVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL;
+ else if (xevent->xcrossing.detail == NotifyInferior)
+ e->detail = ECORE_X_EVENT_DETAIL_INFERIOR;
+ else if (xevent->xcrossing.detail == NotifyNonlinear)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR;
+ else if (xevent->xcrossing.detail == NotifyNonlinearVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL;
+
+ e->time = xevent->xcrossing.time;
+ _ecore_x_event_last_time = e->time;
+ _ecore_x_event_last_win = e->win;
+ _ecore_x_event_last_root_x = e->root.x;
+ _ecore_x_event_last_root_y = e->root.y;
+ ecore_event_add(ECORE_X_EVENT_MOUSE_OUT, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_x_event_handle_focus_in(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Focus_In *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In));
+ if (!e)
+ return;
+
+ e->win = xevent->xfocus.window;
+
+ if (xevent->xfocus.mode == NotifyNormal)
+ e->mode = ECORE_X_EVENT_MODE_NORMAL;
+ else if (xevent->xfocus.mode == NotifyWhileGrabbed)
+ e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED;
+ else if (xevent->xfocus.mode == NotifyGrab)
+ e->mode = ECORE_X_EVENT_MODE_GRAB;
+ else if (xevent->xfocus.mode == NotifyUngrab)
+ e->mode = ECORE_X_EVENT_MODE_UNGRAB;
+
+ if (xevent->xfocus.detail == NotifyAncestor)
+ e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR;
+ else if (xevent->xfocus.detail == NotifyVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL;
+ else if (xevent->xfocus.detail == NotifyInferior)
+ e->detail = ECORE_X_EVENT_DETAIL_INFERIOR;
+ else if (xevent->xfocus.detail == NotifyNonlinear)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR;
+ else if (xevent->xfocus.detail == NotifyNonlinearVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL;
+ else if (xevent->xfocus.detail == NotifyPointer)
+ e->detail = ECORE_X_EVENT_DETAIL_POINTER;
+ else if (xevent->xfocus.detail == NotifyPointerRoot)
+ e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT;
+ else if (xevent->xfocus.detail == NotifyDetailNone)
+ e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE;
+
+ e->time = _ecore_x_event_last_time;
+ _ecore_x_event_last_time = e->time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_focus_out(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Focus_Out *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out));
+ if (!e)
+ return;
+
+ e->win = xevent->xfocus.window;
+
+ if (xevent->xfocus.mode == NotifyNormal)
+ e->mode = ECORE_X_EVENT_MODE_NORMAL;
+ else if (xevent->xfocus.mode == NotifyWhileGrabbed)
+ e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED;
+ else if (xevent->xfocus.mode == NotifyGrab)
+ e->mode = ECORE_X_EVENT_MODE_GRAB;
+ else if (xevent->xfocus.mode == NotifyUngrab)
+ e->mode = ECORE_X_EVENT_MODE_UNGRAB;
+
+ if (xevent->xfocus.detail == NotifyAncestor)
+ e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR;
+ else if (xevent->xfocus.detail == NotifyVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL;
+ else if (xevent->xfocus.detail == NotifyInferior)
+ e->detail = ECORE_X_EVENT_DETAIL_INFERIOR;
+ else if (xevent->xfocus.detail == NotifyNonlinear)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR;
+ else if (xevent->xfocus.detail == NotifyNonlinearVirtual)
+ e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL;
+ else if (xevent->xfocus.detail == NotifyPointer)
+ e->detail = ECORE_X_EVENT_DETAIL_POINTER;
+ else if (xevent->xfocus.detail == NotifyPointerRoot)
+ e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT;
+ else if (xevent->xfocus.detail == NotifyDetailNone)
+ e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE;
+
+ e->time = _ecore_x_event_last_time;
+ _ecore_x_event_last_time = e->time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_keymap_notify(XEvent *xevent EINA_UNUSED)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ /* FIXME: handle this event type */
+}
+
+void
+_ecore_x_event_handle_expose(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Damage *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Damage));
+ if (!e)
+ return;
+
+ e->win = xevent->xexpose.window;
+ e->time = _ecore_x_event_last_time;
+ e->x = xevent->xexpose.x;
+ e->y = xevent->xexpose.y;
+ e->w = xevent->xexpose.width;
+ e->h = xevent->xexpose.height;
+ e->count = xevent->xexpose.count;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_graphics_expose(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Damage *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Damage));
+ if (!e)
+ return;
+
+ e->win = xevent->xgraphicsexpose.drawable;
+ e->time = _ecore_x_event_last_time;
+ e->x = xevent->xgraphicsexpose.x;
+ e->y = xevent->xgraphicsexpose.y;
+ e->w = xevent->xgraphicsexpose.width;
+ e->h = xevent->xgraphicsexpose.height;
+ e->count = xevent->xgraphicsexpose.count;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_visibility_notify(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+// if (xevent->xvisibility.state != VisibilityPartiallyObscured)
+ {
+ Ecore_X_Event_Window_Visibility_Change *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Visibility_Change));
+ if (!e)
+ return;
+
+ e->win = xevent->xvisibility.window;
+ e->time = _ecore_x_event_last_time;
+ if (xevent->xvisibility.state == VisibilityFullyObscured)
+ e->fully_obscured = 1;
+ else
+ e->fully_obscured = 0;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_x_event_handle_create_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Create *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Create));
+ if (!e)
+ return;
+
+ e->win = xevent->xcreatewindow.window;
+ e->parent = xevent->xcreatewindow.parent;
+ if (xevent->xcreatewindow.override_redirect)
+ e->override = 1;
+ else
+ e->override = 0;
+
+ e->x = xevent->xcreatewindow.x;
+ e->y = xevent->xcreatewindow.y;
+ e->w = xevent->xcreatewindow.width;
+ e->h = xevent->xcreatewindow.height;
+ e->border = xevent->xcreatewindow.border_width;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CREATE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_destroy_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Destroy *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Destroy));
+ if (!e)
+ return;
+
+ e->win = xevent->xdestroywindow.window;
+ e->event_win = xevent->xdestroywindow.event;
+ e->time = _ecore_x_event_last_time;
+ if (e->win == _ecore_x_event_last_win)
+ _ecore_x_event_last_win = 0;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DESTROY, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_unmap_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Hide *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Hide));
+ if (!e)
+ return;
+
+ e->win = xevent->xunmap.window;
+ e->event_win = xevent->xunmap.event;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_HIDE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_map_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Show *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Show));
+ if (!e)
+ return;
+
+ e->win = xevent->xmap.window;
+ e->event_win = xevent->xmap.event;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_map_request(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Show_Request *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Show_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xmaprequest.window;
+ e->time = _ecore_x_event_last_time;
+ e->parent = xevent->xmaprequest.parent;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW_REQUEST, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_reparent_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Reparent *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Reparent));
+ if (!e)
+ return;
+
+ e->win = xevent->xreparent.window;
+ e->event_win = xevent->xreparent.event;
+ e->parent = xevent->xreparent.parent;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_REPARENT, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_configure_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Configure *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Configure));
+ if (!e)
+ return;
+
+ e->win = xevent->xconfigure.window;
+ e->event_win = xevent->xconfigure.event;
+ e->abovewin = xevent->xconfigure.above;
+ e->x = xevent->xconfigure.x;
+ e->y = xevent->xconfigure.y;
+ e->w = xevent->xconfigure.width;
+ e->h = xevent->xconfigure.height;
+ e->border = xevent->xconfigure.border_width;
+ e->override = xevent->xconfigure.override_redirect;
+ e->from_wm = xevent->xconfigure.send_event;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_configure_request(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Configure_Request *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Configure_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xconfigurerequest.window;
+ e->parent_win = xevent->xconfigurerequest.parent;
+ e->abovewin = xevent->xconfigurerequest.above;
+ e->x = xevent->xconfigurerequest.x;
+ e->y = xevent->xconfigurerequest.y;
+ e->w = xevent->xconfigurerequest.width;
+ e->h = xevent->xconfigurerequest.height;
+ e->border = xevent->xconfigurerequest.border_width;
+ e->value_mask = xevent->xconfigurerequest.value_mask;
+ e->time = _ecore_x_event_last_time;
+
+ if (xevent->xconfigurerequest.detail == Above)
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ else if (xevent->xconfigurerequest.detail == Below)
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+ else if (xevent->xconfigurerequest.detail == TopIf)
+ e->detail = ECORE_X_WINDOW_STACK_TOP_IF;
+ else if (xevent->xconfigurerequest.detail == BottomIf)
+ e->detail = ECORE_X_WINDOW_STACK_BOTTOM_IF;
+ else if (xevent->xconfigurerequest.detail == Opposite)
+ e->detail = ECORE_X_WINDOW_STACK_OPPOSITE;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gravity_notify(XEvent *xevent EINA_UNUSED)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ /* FIXME: handle this event type */
+}
+
+void
+_ecore_x_event_handle_resize_request(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Resize_Request *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Resize_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xresizerequest.window;
+ e->w = xevent->xresizerequest.width;
+ e->h = xevent->xresizerequest.height;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_circulate_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Stack *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Stack));
+ if (!e)
+ return;
+
+ e->win = xevent->xcirculate.window;
+ e->event_win = xevent->xcirculate.event;
+ if (xevent->xcirculate.place == PlaceOnTop)
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ else
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STACK, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_circulate_request(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Stack_Request *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Stack_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xcirculaterequest.window;
+ e->parent = xevent->xcirculaterequest.parent;
+ if (xevent->xcirculaterequest.place == PlaceOnTop)
+ e->detail = ECORE_X_WINDOW_STACK_ABOVE;
+ else
+ e->detail = ECORE_X_WINDOW_STACK_BELOW;
+
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STACK_REQUEST, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_property_notify(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ {
+ Ecore_X_Event_Window_Property *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Property));
+ if (!e)
+ return;
+
+ e->win = xevent->xproperty.window;
+ e->atom = xevent->xproperty.atom;
+ e->time = xevent->xproperty.time;
+ _ecore_x_event_last_time = e->time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_PROPERTY, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_x_event_handle_selection_clear(XEvent *xevent)
+{
+// Ecore_X_Selection_Intern *d;
+ Ecore_X_Event_Selection_Clear *e;
+ Ecore_X_Atom sel;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_last_event_mouse_move = 0;
+/* errr..... why? paranoia.
+ d = _ecore_x_selection_get(xevent->xselectionclear.selection);
+ if (d && (xevent->xselectionclear.time > d->time))
+ {
+ _ecore_x_selection_set(None, NULL, 0,
+ xevent->xselectionclear.selection);
+ }
+ */
+/* Generate event for app cleanup */
+ e = malloc(sizeof(Ecore_X_Event_Selection_Clear));
+ e->win = xevent->xselectionclear.window;
+ e->time = xevent->xselectionclear.time;
+ e->atom = sel = xevent->xselectionclear.selection;
+ if (sel == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+
+ ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_selection_request(XEvent *xevent)
+{
+ Ecore_X_Event_Selection_Request *e;
+ Ecore_X_Selection_Intern *sd;
+ void *data = NULL;
+ int len;
+ int typesize;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_last_event_mouse_move = 0;
+ /*
+ * Generate a selection request event.
+ */
+ e = malloc(sizeof(Ecore_X_Event_Selection_Request));
+ e->owner = xevent->xselectionrequest.owner;
+ e->requestor = xevent->xselectionrequest.requestor;
+ e->time = xevent->xselectionrequest.time;
+ e->selection = xevent->xselectionrequest.selection;
+ e->target = xevent->xselectionrequest.target;
+ e->property = xevent->xselectionrequest.property;
+ ecore_event_add(ECORE_X_EVENT_SELECTION_REQUEST, e, NULL, NULL);
+
+ if ((sd = _ecore_x_selection_get(xevent->xselectionrequest.selection)) &&
+ (sd->win == xevent->xselectionrequest.owner))
+ {
+ Ecore_X_Selection_Intern *si;
+
+ si = _ecore_x_selection_get(xevent->xselectionrequest.selection);
+ if (si->data)
+ {
+ Ecore_X_Atom property = None;
+ Ecore_X_Atom type;
+
+ /* Set up defaults for strings first */
+ type = xevent->xselectionrequest.target;
+ typesize = 8;
+ len = sd->length;
+
+ if (!ecore_x_selection_convert(xevent->xselectionrequest.selection,
+ xevent->xselectionrequest.target,
+ &data, &len, &type, &typesize))
+ /* Refuse selection, conversion to requested target failed */
+ property = None;
+ else if (data)
+ {
+ /* FIXME: This does not properly handle large data transfers */
+ ecore_x_window_prop_property_set(
+ xevent->xselectionrequest.requestor,
+ xevent->xselectionrequest.
+ property,
+ type,
+ typesize,
+ data,
+ len);
+ property = xevent->xselectionrequest.property;
+ free(data);
+ }
+
+ ecore_x_selection_notify_send(xevent->xselectionrequest.requestor,
+ xevent->xselectionrequest.selection,
+ xevent->xselectionrequest.target,
+ property,
+ xevent->xselectionrequest.time);
+ }
+ }
+}
+
+void
+_ecore_x_event_handle_selection_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Selection_Notify *e;
+ unsigned char *data = NULL;
+ Ecore_X_Atom selection;
+ int num_ret, format;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_last_event_mouse_move = 0;
+ selection = xevent->xselection.selection;
+
+ if (xevent->xselection.target == ECORE_X_ATOM_SELECTION_TARGETS)
+ {
+ format = ecore_x_window_prop_property_get(xevent->xselection.requestor,
+ xevent->xselection.property,
+ XA_ATOM, 32, &data, &num_ret);
+ if (!format)
+ {
+ /* fallback if targets handling is not working and try get the
+ * selection directly */
+ XConvertSelection(_ecore_x_disp, selection,
+ ECORE_X_ATOM_UTF8_STRING,
+ selection,
+ xevent->xselection.requestor,
+ CurrentTime);
+ return;
+ }
+ }
+ else
+ format = ecore_x_window_prop_property_get(xevent->xselection.requestor,
+ xevent->xselection.property,
+ AnyPropertyType, 8, &data,
+ &num_ret);
+
+ e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify));
+ if (!e)
+ return;
+
+ e->win = xevent->xselection.requestor;
+ e->time = xevent->xselection.time;
+ e->atom = selection;
+ e->target = _ecore_x_selection_target_get(xevent->xselection.target);
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ e->selection = ECORE_X_SELECTION_XDND;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+
+ e->data = _ecore_x_selection_parse(e->target, data, num_ret, format);
+
+ ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e,
+ _ecore_x_event_free_selection_notify, NULL);
+}
+
+void
+_ecore_x_event_handle_colormap_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Window_Colormap *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Colormap));
+ if (!e)
+ return;
+
+ e->win = xevent->xcolormap.window;
+ e->cmap = xevent->xcolormap.colormap;
+ e->time = _ecore_x_event_last_time;
+ if (xevent->xcolormap.state == ColormapInstalled)
+ e->installed = EINA_TRUE;
+ else
+ e->installed = EINA_FALSE;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_COLORMAP, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_client_message(XEvent *xevent)
+{
+ _ecore_x_last_event_mouse_move = 0;
+ /* Special client message event handling here. need to put LOTS of if */
+ /* checks here and generate synthetic events per special message known */
+ /* otherwise generate generic client message event. this would handle*/
+ /* netwm, ICCCM, gnomewm, old kde and mwm hint client message protocols */
+ if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_PROTOCOLS) &&
+ (xevent->xclient.format == 32) &&
+ (xevent->xclient.data.l[0] == (long)ECORE_X_ATOM_WM_DELETE_WINDOW))
+ {
+ Ecore_X_Event_Window_Delete_Request *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Delete_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->time = _ecore_x_event_last_time;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL);
+ }
+ else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_MOVERESIZE) &&
+ (xevent->xclient.format == 32) &&
+/* Ignore move and resize with keyboard */
+ (xevent->xclient.data.l[2] < 9))
+ {
+ Ecore_X_Event_Window_Move_Resize_Request *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Move_Resize_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->x = xevent->xclient.data.l[0];
+ e->y = xevent->xclient.data.l[1];
+ e->direction = xevent->xclient.data.l[2];
+ e->button = xevent->xclient.data.l[3];
+ e->source = xevent->xclient.data.l[4];
+ ecore_event_add(ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST, e, NULL, NULL);
+ }
+ /* Xdnd Client Message Handling Begin */
+ /* Message Type: XdndEnter target */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_ENTER)
+ {
+ Ecore_X_Event_Xdnd_Enter *e;
+ Ecore_X_DND_Target *target;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter));
+ if (!e) return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ target = _ecore_x_dnd_target_get();
+ target->state = ECORE_X_DND_TARGET_ENTERED;
+ target->source = xevent->xclient.data.l[0];
+ target->win = xevent->xclient.window;
+ target->version = (int)(xevent->xclient.data.l[1] >> 24);
+ if (target->version > ECORE_X_DND_VERSION)
+ {
+ WRN("DND: Requested version %d, we only support up to %d",
+ target->version, ECORE_X_DND_VERSION);
+ free(e);
+ return;
+ }
+
+ if (xevent->xclient.data.l[1] & 0x1UL)
+ {
+ /* source supports more than 3 types, fetch property */
+ unsigned char *data;
+ Ecore_X_Atom *types;
+ int i, num_ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!(ecore_x_window_prop_property_get(target->source,
+ ECORE_X_ATOM_XDND_TYPE_LIST,
+ XA_ATOM,
+ 32, &data, &num_ret)))
+ {
+ WRN(
+ "DND: Could not fetch data type list from source window, aborting.");
+ free(e);
+ return;
+ }
+
+ types = (Ecore_X_Atom *)data;
+ e->types = calloc(num_ret, sizeof(char *));
+ if (e->types)
+ {
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ for (i = 0; i < num_ret; i++)
+ e->types[i] = XGetAtomName(_ecore_x_disp, types[i]);
+ }
+
+ e->num_types = num_ret;
+ }
+ else
+ {
+ int i = 0;
+
+ e->types = calloc(3, sizeof(char *));
+ if (e->types)
+ {
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ while ((i < 3) && (xevent->xclient.data.l[i + 2]))
+ {
+ e->types[i] = XGetAtomName(_ecore_x_disp,
+ xevent->xclient.data.l[i + 2]);
+ i++;
+ }
+ }
+
+ e->num_types = i;
+ }
+
+ e->win = target->win;
+ e->source = target->source;
+ ecore_event_add(ECORE_X_EVENT_XDND_ENTER, e,
+ _ecore_x_event_free_xdnd_enter, NULL);
+ }
+ /* Message Type: XdndPosition target */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_POSITION)
+ {
+ Ecore_X_Event_Xdnd_Position *e;
+ Ecore_X_DND_Target *target;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ target = _ecore_x_dnd_target_get();
+ if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) ||
+ (target->win != xevent->xclient.window))
+ return;
+
+ target->pos.x = xevent->xclient.data.l[2] >> 16;
+ target->pos.y = xevent->xclient.data.l[2] & 0xFFFFUL;
+ target->action = xevent->xclient.data.l[4]; /* Version 2 */
+
+ target->time = (target->version >= 1) ?
+ (Time)xevent->xclient.data.l[3] : CurrentTime;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Position));
+ if (!e) return;
+
+ e->win = target->win;
+ e->source = target->source;
+ e->position.x = target->pos.x;
+ e->position.y = target->pos.y;
+ e->action = target->action;
+ ecore_event_add(ECORE_X_EVENT_XDND_POSITION, e, NULL, NULL);
+ }
+ /* Message Type: XdndStatus source */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_STATUS)
+ {
+ Ecore_X_Event_Xdnd_Status *e;
+ Ecore_X_DND_Source *source;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ source = _ecore_x_dnd_source_get();
+ /* Make sure source/target match */
+ if ((source->win != xevent->xclient.window) ||
+ (source->dest != (Window)xevent->xclient.data.l[0]))
+ return;
+
+ source->await_status = 0;
+
+ source->will_accept = xevent->xclient.data.l[1] & 0x1UL;
+ source->suppress = (xevent->xclient.data.l[1] & 0x2UL) ? 0 : 1;
+
+ source->rectangle.x = xevent->xclient.data.l[2] >> 16;
+ source->rectangle.y = xevent->xclient.data.l[2] & 0xFFFFUL;
+ source->rectangle.width = xevent->xclient.data.l[3] >> 16;
+ source->rectangle.height = xevent->xclient.data.l[3] & 0xFFFFUL;
+
+ source->accepted_action = xevent->xclient.data.l[4];
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Status));
+ if (!e) return;
+
+ e->win = source->win;
+ e->target = source->dest;
+ e->will_accept = source->will_accept;
+ e->rectangle.x = source->rectangle.x;
+ e->rectangle.y = source->rectangle.y;
+ e->rectangle.width = source->rectangle.width;
+ e->rectangle.height = source->rectangle.height;
+ e->action = source->accepted_action;
+
+ ecore_event_add(ECORE_X_EVENT_XDND_STATUS, e, NULL, NULL);
+ }
+ /* Message Type: XdndLeave target */
+ /* Pretend the whole thing never happened, sort of */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_LEAVE)
+ {
+ Ecore_X_Event_Xdnd_Leave *e;
+ Ecore_X_DND_Target *target;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ target = _ecore_x_dnd_target_get();
+ if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) ||
+ (target->win != xevent->xclient.window))
+ return;
+
+ target->state = ECORE_X_DND_TARGET_IDLE;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Leave));
+ if (!e) return;
+
+ e->win = xevent->xclient.window;
+ e->source = (Window)xevent->xclient.data.l[0];
+ ecore_event_add(ECORE_X_EVENT_XDND_LEAVE, e, NULL, NULL);
+ }
+ /* Message Type: XdndDrop target */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_DROP)
+ {
+ Ecore_X_Event_Xdnd_Drop *e;
+ Ecore_X_DND_Target *target;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ target = _ecore_x_dnd_target_get();
+ /* Match source/target */
+ if ((target->source != (Window)xevent->xclient.data.l[0]) ||
+ (target->win != xevent->xclient.window))
+ return;
+
+ target->time = (target->version >= 1) ?
+ (Time)xevent->xclient.data.l[2] : _ecore_x_event_last_time;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Drop));
+ if (!e) return;
+
+ e->win = target->win;
+ e->source = target->source;
+ e->action = target->action;
+ e->position.x = target->pos.x;
+ e->position.y = target->pos.y;
+ ecore_event_add(ECORE_X_EVENT_XDND_DROP, e, NULL, NULL);
+ }
+ /* Message Type: XdndFinished source */
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_FINISHED)
+ {
+ Ecore_X_Event_Xdnd_Finished *e;
+ Ecore_X_DND_Source *source;
+ Eina_Bool completed = EINA_TRUE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ source = _ecore_x_dnd_source_get();
+ /* Match source/target */
+ if ((source->win != xevent->xclient.window) ||
+ (source->dest != (Window)xevent->xclient.data.l[0]))
+ return;
+
+ if ((source->version < 5) || (xevent->xclient.data.l[1] & 0x1UL))
+ {
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* Target successfully performed drop action */
+ ecore_x_selection_xdnd_clear();
+ source->state = ECORE_X_DND_SOURCE_IDLE;
+ }
+ else if (source->version >= 5)
+ {
+ completed = EINA_FALSE;
+ source->state = ECORE_X_DND_SOURCE_CONVERTING;
+
+ /* FIXME: Probably need to add a timer to switch back to idle
+ * and discard the selection data */
+ }
+
+ e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Finished));
+ if (!e) return;
+
+ e->win = source->win;
+ e->target = source->dest;
+ e->completed = completed;
+ if (source->version >= 5)
+ {
+ source->accepted_action = xevent->xclient.data.l[2];
+ e->action = source->accepted_action;
+ }
+ else
+ {
+ source->accepted_action = 0;
+ e->action = source->action;
+ }
+
+ ecore_event_add(ECORE_X_EVENT_XDND_FINISHED, e, NULL, NULL);
+ }
+ else if (xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_STATE)
+ {
+ Ecore_X_Event_Window_State_Request *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request));
+ if (!e) return;
+
+ e->win = xevent->xclient.window;
+ if (xevent->xclient.data.l[0] == 0)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_REMOVE;
+ else if (xevent->xclient.data.l[0] == 1)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_ADD;
+ else if (xevent->xclient.data.l[0] == 2)
+ e->action = ECORE_X_WINDOW_STATE_ACTION_TOGGLE;
+ else
+ {
+ free(e);
+ return;
+ }
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ e->state[0] = _ecore_x_netwm_state_get(xevent->xclient.data.l[1]);
+ if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN)
+ {
+// char *name;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+// name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[1]);
+// if (name) ERR("Unknown state: %s", name);
+// XFree(name);
+ }
+ e->state[1] = _ecore_x_netwm_state_get(xevent->xclient.data.l[2]);
+ if (e->state[1] == ECORE_X_WINDOW_STATE_UNKNOWN)
+ {
+// char *name;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+// name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[2]);
+// if (name) ERR("Unknown state: %s", name);
+// XFree(name);
+ }
+
+ e->source = xevent->xclient.data.l[3];
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL);
+ }
+ else if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_CHANGE_STATE)
+ && (xevent->xclient.format == 32)
+ && (xevent->xclient.data.l[0] == IconicState))
+ {
+ Ecore_X_Event_Window_State_Request *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->action = ECORE_X_WINDOW_STATE_ACTION_ADD;
+ e->state[0] = ECORE_X_WINDOW_STATE_ICONIFIED;
+
+ ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL);
+ }
+ else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_DESKTOP)
+ && (xevent->xclient.format == 32))
+ {
+ Ecore_X_Event_Desktop_Change *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->desk = xevent->xclient.data.l[0];
+ e->source = xevent->xclient.data.l[1];
+
+ ecore_event_add(ECORE_X_EVENT_DESKTOP_CHANGE, e, NULL, NULL);
+ }
+ else if ((xevent->xclient.message_type ==
+ ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS))
+ {
+ Ecore_X_Event_Frame_Extents_Request *e;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+
+ ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL);
+ }
+ else if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_PROTOCOLS)
+ && ((Ecore_X_Atom)xevent->xclient.data.l[0] ==
+ ECORE_X_ATOM_NET_WM_PING)
+ && (xevent->xclient.format == 32))
+ {
+ Ecore_X_Event_Ping *e;
+ Ecore_X_Window root = 0;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Ping));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->time = xevent->xclient.data.l[1];
+ e->event_win = xevent->xclient.data.l[2];
+
+ /* send a reply anyway - we are alive... eventloop at least */
+ ecore_event_add(ECORE_X_EVENT_PING, e, NULL, NULL);
+ if (ScreenCount(_ecore_x_disp) > 1)
+ {
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ root = ecore_x_window_root_get(e->win);
+ }
+ else
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ if (xevent->xclient.window != root)
+ {
+ xevent->xclient.window = root;
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ xevent);
+ }
+ }
+ else if ((xevent->xclient.message_type ==
+ ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN) &&
+ (xevent->xclient.format == 8))
+ _ecore_x_netwm_startup_info_begin(xevent->xclient.window,
+ xevent->xclient.data.b);
+ else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_STARTUP_INFO) &&
+ (xevent->xclient.format == 8))
+ _ecore_x_netwm_startup_info(xevent->xclient.window,
+ xevent->xclient.data.b);
+ else if ((xevent->xclient.message_type == 27777)
+ && (xevent->xclient.data.l[0] == 0x7162534)
+ && (xevent->xclient.format == 32)
+ && (xevent->xclient.window == _ecore_x_private_win))
+ {
+ /* a grab sync marker */
+ if (xevent->xclient.data.l[1] == 0x10000001)
+ _ecore_x_window_grab_remove(xevent->xclient.data.l[2]);
+ else if (xevent->xclient.data.l[1] == 0x10000002)
+ _ecore_x_key_grab_remove(xevent->xclient.data.l[2]);
+ }
+ else
+ {
+ Ecore_X_Event_Client_Message *e;
+ int i;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Client_Message));
+ if (!e)
+ return;
+
+ e->win = xevent->xclient.window;
+ e->message_type = xevent->xclient.message_type;
+ e->format = xevent->xclient.format;
+ for (i = 0; i < 5; i++)
+ e->data.l[i] = xevent->xclient.data.l[i];
+
+ ecore_event_add(ECORE_X_EVENT_CLIENT_MESSAGE, e, NULL, NULL);
+ }
+}
+
+void
+_ecore_x_event_handle_mapping_notify(XEvent *xevent)
+{
+ Ecore_X_Event_Mapping_Change *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ XRefreshKeyboardMapping((XMappingEvent *)xevent);
+ _ecore_x_modifiers_get();
+ e = calloc(1, sizeof(Ecore_X_Event_Mapping_Change));
+ if (!e) return;
+ switch (xevent->xmapping.request)
+ {
+ case MappingModifier:
+ e->type = ECORE_X_MAPPING_MODIFIER;
+ break;
+
+ case MappingKeyboard:
+ e->type = ECORE_X_MAPPING_KEYBOARD;
+ break;
+
+ case MappingPointer:
+ default:
+ e->type = ECORE_X_MAPPING_MOUSE;
+ break;
+ }
+ e->keycode = xevent->xmapping.first_keycode;
+ e->num = xevent->xmapping.count;
+ ecore_event_add(ECORE_X_EVENT_MAPPING_CHANGE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_shape_change(XEvent *xevent)
+{
+ XShapeEvent *shape_event;
+ Ecore_X_Event_Window_Shape *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ shape_event = (XShapeEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Window_Shape));
+ if (!e)
+ return;
+
+ e->win = shape_event->window;
+ e->time = shape_event->time;
+ switch (shape_event->kind)
+ {
+ case ShapeBounding:
+ e->type = ECORE_X_SHAPE_BOUNDING;
+ break;
+
+ case ShapeClip:
+ e->type = ECORE_X_SHAPE_CLIP;
+ break;
+
+ case ShapeInput:
+ e->type = ECORE_X_SHAPE_INPUT;
+ break;
+
+ default:
+ break;
+ }
+ e->x = shape_event->x;
+ e->y = shape_event->y;
+ e->w = shape_event->width;
+ e->h = shape_event->height;
+ e->shaped = shape_event->shaped;
+ ecore_event_add(ECORE_X_EVENT_WINDOW_SHAPE, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_screensaver_notify(XEvent *xevent)
+{
+#ifdef ECORE_XSS
+ XScreenSaverNotifyEvent *screensaver_event;
+ Ecore_X_Event_Screensaver_Notify *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ screensaver_event = (XScreenSaverNotifyEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Screensaver_Notify));
+ if (!e)
+ return;
+
+ e->win = screensaver_event->window;
+ if ((screensaver_event->state == ScreenSaverOn) ||
+ (screensaver_event->state == ScreenSaverCycle))
+ e->on = EINA_TRUE;
+ else
+ e->on = EINA_FALSE;
+
+ e->time = screensaver_event->time;
+ ecore_event_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, e, NULL, NULL);
+#else /* ifdef ECORE_XSS */
+ xevent = NULL;
+#endif /* ifdef ECORE_XSS */
+}
+
+void
+_ecore_x_event_handle_sync_counter(XEvent *xevent)
+{
+ XSyncCounterNotifyEvent *sync_counter_event;
+ Ecore_X_Event_Sync_Counter *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ sync_counter_event = (XSyncCounterNotifyEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Sync_Counter));
+ if (!e)
+ return;
+
+ e->time = sync_counter_event->time;
+ ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_sync_alarm(XEvent *xevent)
+{
+ XSyncAlarmNotifyEvent *sync_alarm_event;
+ Ecore_X_Event_Sync_Alarm *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ sync_alarm_event = (XSyncAlarmNotifyEvent *)xevent;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Sync_Alarm));
+ if (!e)
+ return;
+
+ e->time = sync_alarm_event->time;
+ e->alarm = sync_alarm_event->alarm;
+ ecore_event_add(ECORE_X_EVENT_SYNC_ALARM, e, NULL, NULL);
+}
+
+#ifdef ECORE_XRANDR
+void
+_ecore_x_event_handle_randr_change(XEvent *xevent)
+{
+ XRRScreenChangeNotifyEvent *randr_event;
+ Ecore_X_Event_Screen_Change *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ randr_event = (XRRScreenChangeNotifyEvent *)xevent;
+ if (!XRRUpdateConfiguration(xevent))
+ ERR("Can't update RR config!");
+
+ e = calloc(1, sizeof(Ecore_X_Event_Screen_Change));
+ if (!e)
+ return;
+
+ e->win = randr_event->window;
+ e->root = randr_event->root;
+ e->size.width = randr_event->width;
+ e->size.height = randr_event->height;
+ e->time = randr_event->timestamp;
+ e->config_time = randr_event->config_timestamp;
+ e->size.width_mm = randr_event->mwidth;
+ e->size.height_mm = randr_event->mheight;
+ e->orientation = randr_event->rotation;
+ e->subpixel_order = randr_event->subpixel_order;
+ ecore_event_add(ECORE_X_EVENT_SCREEN_CHANGE, e, NULL, NULL);
+}
+
+static void
+_ecore_x_event_handle_randr_notify_crtc_change(const XRRNotifyEvent *xevent)
+{
+ const XRRCrtcChangeNotifyEvent *randr_event;
+ Ecore_X_Event_Randr_Crtc_Change *e;
+
+ randr_event = (const XRRCrtcChangeNotifyEvent *)xevent;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change));
+ if (!e)
+ return;
+
+ e->win = randr_event->window;
+ e->crtc = randr_event->crtc;
+ e->mode = randr_event->mode;
+ e->orientation = randr_event->rotation;
+ e->geo.x = randr_event->x;
+ e->geo.y = randr_event->y;
+ e->geo.w = randr_event->width;
+ e->geo.h = randr_event->height;
+ ecore_event_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, e, NULL, NULL);
+}
+
+static void
+_ecore_x_event_handle_randr_notify_output_change(const XRRNotifyEvent *xevent)
+{
+ const XRROutputChangeNotifyEvent *randr_event;
+ Ecore_X_Event_Randr_Output_Change *e;
+
+ randr_event = (const XRROutputChangeNotifyEvent *)xevent;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Change));
+ if (!e)
+ return;
+
+ e->win = randr_event->window;
+ e->output = randr_event->output;
+ e->crtc = randr_event->crtc;
+ e->mode = randr_event->mode;
+ e->orientation = randr_event->rotation;
+ e->connection = randr_event->connection;
+ e->subpixel_order = randr_event->subpixel_order;
+ ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, e, NULL, NULL);
+}
+
+static void
+_ecore_x_event_handle_randr_notify_output_property(const XRRNotifyEvent *xevent)
+{
+ const XRROutputPropertyNotifyEvent *randr_event;
+ Ecore_X_Event_Randr_Output_Property_Notify *e;
+
+ randr_event = (const XRROutputPropertyNotifyEvent *)xevent;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Property_Notify));
+ if (!e)
+ return;
+
+ e->win = randr_event->window;
+ e->output = randr_event->output;
+ e->property = randr_event->property;
+ e->time = randr_event->timestamp;
+ if (randr_event->state == PropertyNewValue)
+ e->state = ECORE_X_RANDR_PROPERTY_CHANGE_ADD;
+ else
+ e->state = ECORE_X_RANDR_PROPERTY_CHANGE_DEL;
+ ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_randr_notify(XEvent *xevent)
+{
+ const XRRNotifyEvent *randr_event;
+
+ _ecore_x_last_event_mouse_move = 0;
+ randr_event = (const XRRNotifyEvent *)xevent;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ switch (randr_event->subtype)
+ {
+ case RRNotify_CrtcChange:
+ _ecore_x_event_handle_randr_notify_crtc_change(randr_event);
+ break;
+
+ case RRNotify_OutputChange:
+ _ecore_x_event_handle_randr_notify_output_change(randr_event);
+ break;
+
+ case RRNotify_OutputProperty:
+ _ecore_x_event_handle_randr_notify_output_property(randr_event);
+ break;
+
+ default:
+ ERR("Unknown XRandR RRNotify subtype: %d.",
+ randr_event->subtype);
+ break;
+ }
+}
+
+#endif /* ifdef ECORE_XRANDR */
+
+#ifdef ECORE_XFIXES
+void
+_ecore_x_event_handle_fixes_selection_notify(XEvent *event)
+{
+ XFixesSelectionNotifyEvent *notify_event =
+ (XFixesSelectionNotifyEvent *)event;
+ Ecore_X_Event_Fixes_Selection_Notify *e;
+ Ecore_X_Atom sel;
+
+ _ecore_x_last_event_mouse_move = 0;
+ /* Nothing here yet */
+
+ e = calloc(1, sizeof(*e));
+ if (!e)
+ return;
+
+ e->win = notify_event->window;
+ e->owner = notify_event->owner;
+ e->time = notify_event->timestamp;
+ e->selection_time = notify_event->selection_timestamp;
+ e->atom = sel = notify_event->selection;
+ if (sel == ECORE_X_ATOM_SELECTION_PRIMARY)
+ e->selection = ECORE_X_SELECTION_PRIMARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY)
+ e->selection = ECORE_X_SELECTION_SECONDARY;
+ else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ e->selection = ECORE_X_SELECTION_CLIPBOARD;
+ else
+ e->selection = ECORE_X_SELECTION_OTHER;
+ e->reason = notify_event->subtype;
+
+ ecore_event_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, e, NULL, NULL);
+}
+
+#endif /* ifdef ECORE_XFIXES */
+
+#ifdef ECORE_XDAMAGE
+void
+_ecore_x_event_handle_damage_notify(XEvent *event)
+{
+ XDamageNotifyEvent *damage_event;
+ Ecore_X_Event_Damage *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ damage_event = (XDamageNotifyEvent *)event;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Damage));
+ if (!e)
+ return;
+
+ e->level = damage_event->level;
+ e->drawable = damage_event->drawable;
+ e->damage = damage_event->damage;
+ e->more = damage_event->more;
+ e->time = damage_event->timestamp;
+ e->area.x = damage_event->area.x;
+ e->area.y = damage_event->area.y;
+ e->area.width = damage_event->area.width;
+ e->area.height = damage_event->area.height;
+ e->geometry.x = damage_event->geometry.x;
+ e->geometry.y = damage_event->geometry.y;
+ e->geometry.width = damage_event->geometry.width;
+ e->geometry.height = damage_event->geometry.height;
+
+ ecore_event_add(ECORE_X_EVENT_DAMAGE_NOTIFY, e, NULL, NULL);
+}
+
+#endif /* ifdef ECORE_XDAMAGE */
+
+static void
+_ecore_x_event_free_generic_event(void *data,
+ void *ev)
+{
+#ifdef ECORE_XI2
+ Ecore_X_Event_Generic *e = (Ecore_X_Event_Generic *)ev;
+
+ if (data)
+ {
+ if (e->data)
+ XFreeEventData(_ecore_x_disp, (XGenericEventCookie *)data);
+ free(data);
+ }
+ free(e);
+#else
+ return;
+ data = NULL; ev = NULL;
+#endif /* ifdef ECORE_XI2 */
+}
+
+void
+_ecore_x_event_handle_generic_event(XEvent *event)
+{
+#ifdef ECORE_XI2
+ XGenericEvent *generic_event;
+ Ecore_X_Event_Generic *e;
+ XGenericEventCookie *data;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ generic_event = (XGenericEvent *)event;
+
+ e = calloc(1, sizeof(Ecore_X_Event_Generic));
+ if (!e)
+ return;
+
+ if (XGetEventData(_ecore_x_disp, &(event->xcookie)))
+ {
+ e->cookie = event->xcookie.cookie;
+ e->data = event->xcookie.data;
+ }
+ else
+ {
+ e->cookie = 0;
+ e->data = NULL;
+ }
+
+ e->extension = generic_event->extension;
+ e->evtype = generic_event->evtype;
+
+ if (e->extension == _ecore_x_xi2_opcode)
+ _ecore_x_input_handler(event);
+
+ data = malloc(sizeof(XGenericEventCookie));
+ if (data) memcpy(data, &(event->xcookie), sizeof(XGenericEventCookie));
+ ecore_event_add(ECORE_X_EVENT_GENERIC,
+ e,
+ _ecore_x_event_free_generic_event,
+ data);
+#else
+ return;
+ event = NULL;
+#endif /* ifdef ECORE_XI2 */
+}
+
+#ifdef ECORE_XGESTURE
+void
+_ecore_x_event_handle_gesture_notify_flick(XEvent *xevent)
+{
+ XGestureNotifyFlickEvent *xfe;
+ Ecore_X_Event_Gesture_Notify_Flick *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xfe = (XGestureNotifyFlickEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Flick));
+ if (!e)
+ return;
+
+ e->win = xfe->window;
+ e->time = xfe->time;
+ e->subtype = xfe->kind;
+ e->num_fingers = xfe->num_finger;
+ e->distance = xfe->distance;
+ e->duration = xfe->duration;
+ e->direction = xfe->direction;
+ e->angle = XFixedToDouble(xfe->angle);
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_FLICK, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_pan(XEvent *xevent)
+{
+ XGestureNotifyPanEvent *xpe;
+ Ecore_X_Event_Gesture_Notify_Pan *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xpe = (XGestureNotifyPanEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Pan));
+ if (!e)
+ return;
+
+ e->win = xpe->window;
+ e->time = xpe->time;
+ e->subtype = xpe->kind;
+ e->num_fingers = xpe->num_finger;
+ e->dx = xpe->dx;
+ e->dy = xpe->dy;
+ e->distance = xpe->distance;
+ e->duration = xpe->duration;
+ e->direction = xpe->direction;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PAN, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_pinchrotation(XEvent *xevent)
+{
+ XGestureNotifyPinchRotationEvent *xpre;
+ Ecore_X_Event_Gesture_Notify_PinchRotation *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xpre = (XGestureNotifyPinchRotationEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_PinchRotation));
+ if (!e)
+ return;
+
+ e->win = xpre->window;
+ e->time = xpre->time;
+ e->subtype = xpre->kind;
+ e->num_fingers = xpre->num_finger;
+ e->distance = xpre->distance;
+ e->cx = xpre->cx;
+ e->cy = xpre->cy;
+ e->zoom = XFixedToDouble(xpre->zoom);
+ e->angle = XFixedToDouble(xpre->angle);
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_tap(XEvent *xevent)
+{
+ XGestureNotifyTapEvent *xte;
+ Ecore_X_Event_Gesture_Notify_Tap *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xte = (XGestureNotifyTapEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Tap));
+ if (!e)
+ return;
+
+ e->win = xte->window;
+ e->time = xte->time;
+ e->subtype = xte->kind;
+ e->num_fingers = xte->num_finger;
+ e->cx = xte->cx;
+ e->cy = xte->cy;
+ e->tap_repeat = xte->tap_repeat;
+ e->interval = xte->interval;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAP, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_tapnhold(XEvent *xevent)
+{
+ XGestureNotifyTapNHoldEvent *xthe;
+ Ecore_X_Event_Gesture_Notify_TapNHold *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xthe = (XGestureNotifyTapNHoldEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_TapNHold));
+ if (!e)
+ return;
+
+ e->win = xthe->window;
+ e->time = xthe->time;
+ e->subtype = xthe->kind;
+ e->num_fingers = xthe->num_finger;
+ e->cx = xthe->cx;
+ e->cy = xthe->cy;
+ e->interval = xthe->interval;
+ e->hold_time = xthe->holdtime;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_hold(XEvent *xevent)
+{
+ XGestureNotifyHoldEvent *xhe;
+ Ecore_X_Event_Gesture_Notify_Hold *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xhe = (XGestureNotifyHoldEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Hold));
+ if (!e)
+ return;
+
+ e->win = xhe->window;
+ e->time = xhe->time;
+ e->subtype = xhe->kind;
+ e->num_fingers = xhe->num_finger;
+ e->cx = xhe->cx;
+ e->cy = xhe->cy;
+ e->hold_time = xhe->holdtime;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_HOLD, e, NULL, NULL);
+}
+
+void
+_ecore_x_event_handle_gesture_notify_group(XEvent *xevent)
+{
+ XGestureNotifyGroupEvent *xge;
+ Ecore_X_Event_Gesture_Notify_Group *e;
+
+ _ecore_x_last_event_mouse_move = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xge = (XGestureNotifyGroupEvent *)xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Group));
+ if (!e)
+ return;
+
+ e->win = xge->window;
+ e->time = xge->time;
+ e->subtype = xge->kind;
+ e->num_groups = xge->num_group;
+ e->group_id = xge->groupid;
+
+ ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_GROUP, e, NULL, NULL);
+}
+
+#endif /* ifdef ECORE_XGESTURE */
+#ifdef ECORE_XKB
+void
+_ecore_x_event_handle_xkb(XEvent *xevent)
+{
+ XkbEvent *xkbev;
+ Ecore_X_Event_Xkb *e;
+
+ xkbev = (XkbEvent *) xevent;
+ e = calloc(1, sizeof(Ecore_X_Event_Xkb));
+ if (!e)
+ return;
+ e->group = xkbev->state.group;
+ if (xkbev->any.xkb_type == XkbStateNotify)
+ ecore_event_add(ECORE_X_EVENT_XKB_STATE_NOTIFY, e, NULL, NULL);
+ else if ((xkbev->any.xkb_type == XkbNewKeyboardNotify) ||
+ (xkbev->any.xkb_type == XkbMapNotify))
+ {
+ if (xkbev->any.xkb_type == XkbMapNotify)
+ {
+ XkbMapNotifyEvent *xkbmapping;
+
+ xkbmapping = (XkbMapNotifyEvent *)xkbev;
+ XkbRefreshKeyboardMapping(xkbmapping);
+ }
+ ecore_event_add(ECORE_X_EVENT_XKB_NEWKBD_NOTIFY, e, NULL, NULL);
+ }
+}
+#endif /* ifdef ECORE_XKB */
diff --git a/src/lib/ecore_x/xlib/ecore_x_fixes.c b/src/lib/ecore_x/xlib/ecore_x_fixes.c
new file mode 100644
index 0000000000..da0a6c3ac9
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_fixes.c
@@ -0,0 +1,365 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+static int _fixes_available;
+#ifdef ECORE_XFIXES
+static int _fixes_major, _fixes_minor;
+#endif /* ifdef ECORE_XFIXES */
+
+void
+_ecore_x_fixes_init(void)
+{
+#ifdef ECORE_XFIXES
+ _fixes_major = 3;
+ _fixes_minor = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XFixesQueryVersion(_ecore_x_disp, &_fixes_major, &_fixes_minor))
+ {
+ _fixes_available = 1;
+
+ ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = ecore_event_type_new();
+ }
+ else
+ _fixes_available = 0;
+
+#else /* ifdef ECORE_XFIXES */
+ _fixes_available = 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+#ifdef ECORE_XFIXES
+/* I don't know what to call this function. */
+static XRectangle *
+_ecore_x_rectangle_ecore_to_x(Ecore_X_Rectangle *rects,
+ int num)
+{
+ XRectangle *xrect;
+ int i;
+
+ if (num == 0)
+ return NULL;
+
+ xrect = malloc(sizeof(XRectangle) * num);
+ if (!xrect)
+ return NULL;
+
+ for (i = 0; i < num; i++)
+ {
+ xrect[i].x = rects[i].x;
+ xrect[i].y = rects[i].y;
+ xrect[i].width = rects[i].width;
+ xrect[i].height = rects[i].height;
+ }
+ return xrect;
+}
+
+static Ecore_X_Rectangle *
+_ecore_x_rectangle_x_to_ecore(XRectangle *xrect,
+ int num)
+{
+ Ecore_X_Rectangle *rects;
+ int i;
+
+ if (num == 0)
+ return NULL;
+
+ rects = malloc(sizeof(Ecore_X_Rectangle) * num);
+ if (!rects)
+ return NULL;
+
+ for (i = 0; i < num; i++)
+ {
+ rects[i].x = xrect[i].x;
+ rects[i].y = xrect[i].y;
+ rects[i].width = xrect[i].width;
+ rects[i].height = xrect[i].height;
+ }
+ return rects;
+}
+
+#endif /* ifdef ECORE_XFIXES */
+
+EAPI Eina_Bool
+ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection)
+{
+#ifdef ECORE_XFIXES
+ if (_fixes_available)
+ {
+ XFixesSelectSelectionInput (_ecore_x_disp,
+ DefaultRootWindow(_ecore_x_disp),
+ selection,
+ XFixesSetSelectionOwnerNotifyMask |
+ XFixesSelectionWindowDestroyNotifyMask |
+ XFixesSelectionClientCloseNotifyMask);
+ return EINA_TRUE;
+ }
+#endif
+ return EINA_FALSE;
+}
+
+EAPI Ecore_X_Region
+ecore_x_region_new(Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XFIXES
+ Ecore_X_Region region;
+ XRectangle *xrect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xrect = _ecore_x_rectangle_ecore_to_x(rects, num);
+ region = XFixesCreateRegion(_ecore_x_disp, xrect, num);
+ free(xrect);
+ return region;
+#else /* ifdef ECORE_XFIXES */
+ return 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI Ecore_X_Region
+ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap)
+{
+#ifdef ECORE_XFIXES
+ Ecore_X_Region region;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ region = XFixesCreateRegionFromBitmap(_ecore_x_disp, bitmap);
+ return region;
+#else /* ifdef ECORE_XFIXES */
+ return 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI Ecore_X_Region
+ecore_x_region_new_from_window(Ecore_X_Window win,
+ Ecore_X_Region_Type type)
+{
+#ifdef ECORE_XFIXES
+ Ecore_X_Region region;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ region = XFixesCreateRegionFromWindow(_ecore_x_disp, win, type);
+ return region;
+#else /* ifdef ECORE_XFIXES */
+ return 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI Ecore_X_Region
+ecore_x_region_new_from_gc(Ecore_X_GC gc)
+{
+#ifdef ECORE_XFIXES
+ Ecore_X_Region region;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ region = XFixesCreateRegionFromGC(_ecore_x_disp, gc);
+ return region;
+#else /* ifdef ECORE_XFIXES */
+ return 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI Ecore_X_Region
+ecore_x_region_new_from_picture(Ecore_X_Picture picture)
+{
+#ifdef ECORE_XFIXES
+ Ecore_X_Region region;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ region = XFixesCreateRegionFromPicture(_ecore_x_disp, picture);
+ return region;
+#else /* ifdef ECORE_XFIXES */
+ return 0;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_free(Ecore_X_Region region)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesDestroyRegion(_ecore_x_disp, region);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_set(Ecore_X_Region region,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ECORE_XFIXES
+ XRectangle *xrect = _ecore_x_rectangle_ecore_to_x(rects, num);
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesSetRegion(_ecore_x_disp, region, xrect, num);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_copy(Ecore_X_Region dest,
+ Ecore_X_Region source)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesCopyRegion(_ecore_x_disp, dest, source);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_combine(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesUnionRegion(_ecore_x_disp, dest, source1, source2);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_intersect(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesIntersectRegion(_ecore_x_disp, dest, source1, source2);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_subtract(Ecore_X_Region dest,
+ Ecore_X_Region source1,
+ Ecore_X_Region source2)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesSubtractRegion(_ecore_x_disp, dest, source1, source2);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_invert(Ecore_X_Region dest,
+ Ecore_X_Rectangle *bounds,
+ Ecore_X_Region source)
+{
+#ifdef ECORE_XFIXES
+ XRectangle *xbound;
+ int num = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ while (bounds + num)
+ num++;
+ xbound = _ecore_x_rectangle_ecore_to_x(bounds, num);
+
+ XFixesInvertRegion(_ecore_x_disp, dest, xbound, source);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_translate(Ecore_X_Region region,
+ int dx,
+ int dy)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesTranslateRegion(_ecore_x_disp, region, dx, dy);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_extents(Ecore_X_Region dest,
+ Ecore_X_Region source)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesRegionExtents(_ecore_x_disp, dest, source);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI Ecore_X_Rectangle *
+ecore_x_region_fetch(Ecore_X_Region region,
+ int *num,
+ Ecore_X_Rectangle *bounds){
+#ifdef ECORE_XFIXES
+ Ecore_X_Rectangle *rects;
+ XRectangle *xrect, xbound;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xrect = XFixesFetchRegionAndBounds(_ecore_x_disp, region, num, &xbound);
+ rects = _ecore_x_rectangle_x_to_ecore(xrect, *num);
+ (*bounds).x = xbound.x;
+ (*bounds).y = xbound.y;
+ (*bounds).width = xbound.width;
+ (*bounds).height = xbound.height;
+ return rects;
+#else /* ifdef ECORE_XFIXES */
+ return NULL;
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_expand(Ecore_X_Region dest,
+ Ecore_X_Region source,
+ unsigned int left,
+ unsigned int right,
+ unsigned int top,
+ unsigned int bottom)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesExpandRegion(_ecore_x_disp, dest, source, left, right, top, bottom);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_gc_clip_set(Ecore_X_Region region,
+ Ecore_X_GC gc,
+ int x_origin,
+ int y_origin)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesSetGCClipRegion(_ecore_x_disp, gc, x_origin, y_origin, region);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_window_shape_set(Ecore_X_Region region,
+ Ecore_X_Window win,
+ Ecore_X_Shape_Type type,
+ int x_offset,
+ int y_offset)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesSetWindowShapeRegion(_ecore_x_disp,
+ win,
+ type,
+ x_offset,
+ y_offset,
+ region);
+#endif /* ifdef ECORE_XFIXES */
+}
+
+EAPI void
+ecore_x_region_picture_clip_set(Ecore_X_Region region,
+ Ecore_X_Picture picture,
+ int x_origin,
+ int y_origin)
+{
+#ifdef ECORE_XFIXES
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFixesSetPictureClipRegion(_ecore_x_disp,
+ picture,
+ x_origin,
+ y_origin,
+ region);
+#endif /* ifdef ECORE_XFIXES */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_gc.c b/src/lib/ecore_x/xlib/ecore_x_gc.c
new file mode 100644
index 0000000000..539636648f
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_gc.c
@@ -0,0 +1,171 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+/**
+ * Creates a new default graphics context associated with the given
+ * drawable.
+ * @param draw Drawable to create graphics context with. If @c 0 is
+ * given instead, the default root window is used.
+ * @param value_mask Bitmask values.
+ * @param value_list List of values. The order of values must be the
+ * same than the corresponding bitmaks.
+ * @return The new default graphics context.
+ */
+EAPI Ecore_X_GC
+ecore_x_gc_new(Ecore_X_Drawable draw,
+ Ecore_X_GC_Value_Mask value_mask,
+ const unsigned int *value_list)
+{
+ XGCValues gcv;
+ int mask;
+ int idx;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!draw)
+ draw = DefaultRootWindow(_ecore_x_disp);
+
+ memset(&gcv, 0, sizeof (gcv));
+
+ for (i = 0, idx = 0, mask = 1; i <= 22; i++, mask <<= 1)
+ {
+ switch (mask & value_mask)
+ {
+ case ECORE_X_GC_VALUE_MASK_FUNCTION:
+ gcv.function = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_PLANE_MASK:
+ gcv.plane_mask = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FOREGROUND:
+ gcv.foreground = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_BACKGROUND:
+ gcv.background = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_LINE_WIDTH:
+ gcv.line_width = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_LINE_STYLE:
+ gcv.line_style = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CAP_STYLE:
+ gcv.cap_style = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_JOIN_STYLE:
+ gcv.join_style = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FILL_STYLE:
+ gcv.fill_style = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FILL_RULE:
+ gcv.fill_rule = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE:
+ gcv.tile = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_STIPPLE:
+ gcv.stipple = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X:
+ gcv.ts_x_origin = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y:
+ gcv.ts_y_origin = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_FONT:
+ gcv.font = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE:
+ gcv.subwindow_mode = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES:
+ gcv.graphics_exposures = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X:
+ gcv.clip_x_origin = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y:
+ gcv.clip_y_origin = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_CLIP_MASK:
+ gcv.clip_mask = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_DASH_OFFSET:
+ gcv.dash_offset = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_DASH_LIST:
+ gcv.dashes = value_list[idx];
+ idx++;
+ break;
+
+ case ECORE_X_GC_VALUE_MASK_ARC_MODE:
+ gcv.arc_mode = value_list[idx];
+ idx++;
+ break;
+ }
+ }
+
+ return XCreateGC(_ecore_x_disp, draw, value_mask, &gcv);
+}
+
+/**
+ * Deletes and frees the given graphics context.
+ * @param gc The given graphics context.
+ */
+EAPI void
+ecore_x_gc_free(Ecore_X_GC gc)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFreeGC(_ecore_x_disp, gc);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_gesture.c b/src/lib/ecore_x/xlib/ecore_x_gesture.c
new file mode 100644
index 0000000000..dbde8b0db2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_gesture.c
@@ -0,0 +1,137 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+
+static Eina_Bool _gesture_available = EINA_FALSE;
+
+#ifdef ECORE_XGESTURE
+static int _gesture_major, _gesture_minor, _gesture_patch;
+int _gesture_version;
+#endif /* ifdef ECORE_XGESTURE */
+
+void
+_ecore_x_gesture_init(void)
+{
+#ifdef ECORE_XGESTURE
+ _gesture_major = 0;
+ _gesture_minor = 0;
+ _gesture_patch = 0;
+ _gesture_version = 0;
+
+ if (XGestureQueryVersion(_ecore_x_disp, &_gesture_major, &_gesture_minor, &_gesture_patch))
+ {
+ _gesture_version = (_gesture_major << 16) | _gesture_minor;
+ _gesture_available = EINA_TRUE;
+ }
+ else
+ _gesture_available = EINA_FALSE;
+#else /* ifdef ECORE_XGESTURE */
+ _gesture_available = EINA_FALSE;
+#endif /* ifdef ECORE_XGESTURE */
+}
+
+/*
+ * @brief Query whether gesture is available or not.
+ *
+ * @return @c EINA_TRUE, if extension is available, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_gesture_supported(void)
+{
+ return _gesture_available;
+}
+
+EAPI Eina_Bool
+ecore_x_gesture_events_select(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Mask mask)
+{
+#ifdef ECORE_XGESTURE
+ if (!_gesture_available)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGestureSelectEvents(_ecore_x_disp, win, mask);
+
+ return EINA_TRUE;
+#else /* ifdef ECORE_XGESTURE */
+ (void) win;
+ (void) mask;
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XGESTURE */
+}
+
+EAPI Ecore_X_Gesture_Event_Mask
+ecore_x_gesture_events_selected_get(Ecore_X_Window win)
+{
+#ifdef ECORE_XGESTURE
+ Ecore_X_Gesture_Event_Mask mask;
+
+ if (!_gesture_available)
+ return ECORE_X_GESTURE_EVENT_MASK_NONE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (GestureSuccess != XGestureGetSelectedEvents(_ecore_x_disp, win, &mask))
+ {
+ mask = ECORE_X_GESTURE_EVENT_MASK_NONE;
+ return mask;
+ }
+
+ return mask;
+#else /* ifdef ECORE_XGESTURE */
+ (void) win;
+ return ECORE_X_GESTURE_EVENT_MASK_NONE;
+#endif /* ifdef ECORE_XGESTURE */
+}
+
+EAPI Eina_Bool
+ecore_x_gesture_event_grab(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Type type,
+ int num_fingers)
+{
+#ifdef ECORE_XGESTURE
+ if (!_gesture_available)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (GestureGrabSuccess != XGestureGrabEvent(_ecore_x_disp, win, type, num_fingers, CurrentTime))
+ {
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#else /* ifdef ECORE_XGESTURE */
+ (void) win;
+ (void) type;
+ (void) num_fingers;
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XGESTURE */
+}
+
+EAPI Eina_Bool
+ecore_x_gesture_event_ungrab(Ecore_X_Window win,
+ Ecore_X_Gesture_Event_Type type,
+ int num_fingers)
+{
+#ifdef ECORE_XGESTURE
+ Ecore_X_Gesture_Event_Mask mask;
+
+ if (!_gesture_available)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (GestureUngrabSuccess != XGestureUngrabEvent(_ecore_x_disp, win, type, num_fingers, CurrentTime))
+ {
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#else /* ifdef ECORE_XGESTURE */
+ (void) win;
+ (void) type;
+ (void) num_fingers;
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XGESTURE */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_icccm.c b/src/lib/ecore_x/xlib/ecore_x_icccm.c
new file mode 100644
index 0000000000..8d6ea1f50e
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_icccm.c
@@ -0,0 +1,1214 @@
+/*
+ * Various ICCCM related functions.
+ *
+ * This is ALL the code involving anything ICCCM related. for both WM and
+ * client.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+EAPI void
+ecore_x_icccm_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
+
+EAPI void
+ecore_x_icccm_state_set(Ecore_X_Window win,
+ Ecore_X_Window_State_Hint state)
+{
+ unsigned long c[2];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ c[0] = WithdrawnState;
+ else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ c[0] = NormalState;
+ else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ c[0] = IconicState;
+
+ c[1] = None;
+ XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
+ ECORE_X_ATOM_WM_STATE, 32, PropModeReplace,
+ (unsigned char *)c, 2);
+}
+
+EAPI Ecore_X_Window_State_Hint
+ecore_x_icccm_state_get(Ecore_X_Window win)
+{
+ unsigned char *prop_ret = NULL;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ Ecore_X_Window_State_Hint hint;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ hint = ECORE_X_WINDOW_STATE_HINT_NONE;
+ XGetWindowProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
+ 0, 0x7fffffff, False, ECORE_X_ATOM_WM_STATE,
+ &type_ret, &format_ret, &num_ret, &bytes_after,
+ &prop_ret);
+ if ((prop_ret) && (num_ret == 2))
+ {
+ if (prop_ret[0] == WithdrawnState)
+ hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ else if (prop_ret[0] == NormalState)
+ hint = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ else if (prop_ret[0] == IconicState)
+ hint = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return hint;
+}
+
+EAPI void
+ecore_x_icccm_delete_window_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ ECORE_X_EVENT_MASK_NONE,
+ ECORE_X_ATOM_WM_DELETE_WINDOW,
+ t, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_icccm_take_focus_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ ECORE_X_EVENT_MASK_NONE,
+ ECORE_X_ATOM_WM_TAKE_FOCUS,
+ t, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_icccm_save_yourself_send(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
+ ECORE_X_EVENT_MASK_NONE,
+ ECORE_X_ATOM_WM_SAVE_YOURSELF,
+ t, 0, 0, 0);
+}
+
+EAPI void
+ecore_x_icccm_move_resize_send(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XEvent ev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ev.type = ConfigureNotify;
+ ev.xconfigure.display = _ecore_x_disp;
+ ev.xconfigure.event = win;
+ ev.xconfigure.window = win;
+ ev.xconfigure.x = x;
+ ev.xconfigure.y = y;
+ ev.xconfigure.width = w;
+ ev.xconfigure.height = h;
+ ev.xconfigure.border_width = 0;
+ ev.xconfigure.above = None;
+ ev.xconfigure.override_redirect = False;
+ XSendEvent(_ecore_x_disp, win, False, StructureNotifyMask, &ev);
+}
+
+EAPI void
+ecore_x_icccm_hints_set(Ecore_X_Window win,
+ Eina_Bool accepts_focus,
+ Ecore_X_Window_State_Hint initial_state,
+ Ecore_X_Pixmap icon_pixmap,
+ Ecore_X_Pixmap icon_mask,
+ Ecore_X_Window icon_window,
+ Ecore_X_Window window_group,
+ Eina_Bool is_urgent)
+{
+ XWMHints *hints;
+
+ hints = XAllocWMHints();
+ if (!hints)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ hints->flags = InputHint | StateHint;
+ hints->input = accepts_focus;
+ if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
+ hints->initial_state = WithdrawnState;
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
+ hints->initial_state = NormalState;
+ else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
+ hints->initial_state = IconicState;
+
+ if (icon_pixmap != 0)
+ {
+ hints->icon_pixmap = icon_pixmap;
+ hints->flags |= IconPixmapHint;
+ }
+
+ if (icon_mask != 0)
+ {
+ hints->icon_mask = icon_mask;
+ hints->flags |= IconMaskHint;
+ }
+
+ if (icon_window != 0)
+ {
+ hints->icon_window = icon_window;
+ hints->flags |= IconWindowHint;
+ }
+
+ if (window_group != 0)
+ {
+ hints->window_group = window_group;
+ hints->flags |= WindowGroupHint;
+ }
+
+ if (is_urgent)
+ hints->flags |= XUrgencyHint;
+
+ XSetWMHints(_ecore_x_disp, win, hints);
+ XFree(hints);
+}
+
+EAPI Eina_Bool
+ecore_x_icccm_hints_get(Ecore_X_Window win,
+ Eina_Bool *accepts_focus,
+ Ecore_X_Window_State_Hint *initial_state,
+ Ecore_X_Pixmap *icon_pixmap,
+ Ecore_X_Pixmap *icon_mask,
+ Ecore_X_Window *icon_window,
+ Ecore_X_Window *window_group,
+ Eina_Bool *is_urgent)
+{
+ XWMHints *hints;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (accepts_focus)
+ *accepts_focus = EINA_TRUE;
+
+ if (initial_state)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+
+ if (icon_pixmap)
+ *icon_pixmap = 0;
+
+ if (icon_mask)
+ *icon_mask = 0;
+
+ if (icon_window)
+ *icon_window = 0;
+
+ if (window_group)
+ *window_group = 0;
+
+ if (is_urgent)
+ *is_urgent = EINA_FALSE;
+
+ hints = XGetWMHints(_ecore_x_disp, win);
+ if (hints)
+ {
+ if ((hints->flags & InputHint) && (accepts_focus))
+ {
+ if (hints->input)
+ *accepts_focus = EINA_TRUE;
+ else
+ *accepts_focus = EINA_FALSE;
+ }
+
+ if ((hints->flags & StateHint) && (initial_state))
+ {
+ if (hints->initial_state == WithdrawnState)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
+ else if (hints->initial_state == NormalState)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
+ else if (hints->initial_state == IconicState)
+ *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
+ }
+
+ if ((hints->flags & IconPixmapHint) && (icon_pixmap))
+ *icon_pixmap = hints->icon_pixmap;
+
+ if ((hints->flags & IconMaskHint) && (icon_mask))
+ *icon_mask = hints->icon_mask;
+
+ if ((hints->flags & IconWindowHint) && (icon_window))
+ *icon_window = hints->icon_window;
+
+ if ((hints->flags & WindowGroupHint) && (window_group))
+ *window_group = hints->window_group;
+
+ if ((hints->flags & XUrgencyHint) && (is_urgent))
+ *is_urgent = EINA_TRUE;
+
+ XFree(hints);
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,
+ Eina_Bool request_pos,
+ Ecore_X_Gravity gravity,
+ int min_w,
+ int min_h,
+ int max_w,
+ int max_h,
+ int base_w,
+ int base_h,
+ int step_x,
+ int step_y,
+ double min_aspect,
+ double max_aspect)
+{
+ XSizeHints hint;
+ long mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
+ memset(&hint, 0, sizeof(XSizeHints));
+
+ hint.flags = 0;
+ if (request_pos)
+ hint.flags |= USPosition;
+
+ if (gravity != ECORE_X_GRAVITY_NW)
+ {
+ hint.flags |= PWinGravity;
+ hint.win_gravity = gravity;
+ }
+
+ if ((min_w > 0) || (min_h > 0))
+ {
+ hint.flags |= PMinSize;
+ hint.min_width = min_w;
+ hint.min_height = min_h;
+ }
+
+ if ((max_w > 0) || (max_h > 0))
+ {
+ hint.flags |= PMaxSize;
+ hint.max_width = max_w;
+ hint.max_height = max_h;
+ }
+
+ if ((base_w > 0) || (base_h > 0))
+ {
+ hint.flags |= PBaseSize;
+ hint.base_width = base_w;
+ hint.base_height = base_h;
+ }
+
+ if ((step_x > 1) || (step_y > 1))
+ {
+ hint.flags |= PResizeInc;
+ hint.width_inc = step_x;
+ hint.height_inc = step_y;
+ }
+
+ if ((min_aspect > 0.0) || (max_aspect > 0.0))
+ {
+ hint.flags |= PAspect;
+ hint.min_aspect.x = min_aspect * 10000;
+ hint.min_aspect.y = 10000;
+ hint.max_aspect.x = max_aspect * 10000;
+ hint.max_aspect.y = 10000;
+ }
+
+ XSetWMNormalHints(_ecore_x_disp, win, &hint);
+}
+
+EAPI Eina_Bool
+ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,
+ Eina_Bool *request_pos,
+ Ecore_X_Gravity *gravity,
+ int *min_w,
+ int *min_h,
+ int *max_w,
+ int *max_h,
+ int *base_w,
+ int *base_h,
+ int *step_x,
+ int *step_y,
+ double *min_aspect,
+ double *max_aspect)
+{
+ XSizeHints hint;
+ long mask;
+
+ int minw = 0, minh = 0;
+ int maxw = 32767, maxh = 32767;
+ int basew = -1, baseh = -1;
+ int stepx = -1, stepy = -1;
+ double mina = 0.0, maxa = 0.0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
+ return EINA_FALSE;
+
+ if ((hint.flags & USPosition) || ((hint.flags & PPosition)))
+ {
+ if (request_pos)
+ *request_pos = EINA_TRUE;
+ }
+ else if (request_pos)
+ *request_pos = EINA_FALSE;
+
+ if (hint.flags & PWinGravity)
+ {
+ if (gravity)
+ *gravity = hint.win_gravity;
+ }
+ else if (gravity)
+ *gravity = ECORE_X_GRAVITY_NW;
+
+ if (hint.flags & PMinSize)
+ {
+ minw = hint.min_width;
+ minh = hint.min_height;
+ }
+
+ if (hint.flags & PMaxSize)
+ {
+ maxw = hint.max_width;
+ maxh = hint.max_height;
+ if (maxw < minw)
+ maxw = minw;
+
+ if (maxh < minh)
+ maxh = minh;
+ }
+
+ if (hint.flags & PBaseSize)
+ {
+ basew = hint.base_width;
+ baseh = hint.base_height;
+ if (basew > minw)
+ minw = basew;
+
+ if (baseh > minh)
+ minh = baseh;
+ }
+
+ if (hint.flags & PResizeInc)
+ {
+ stepx = hint.width_inc;
+ stepy = hint.height_inc;
+ if (stepx < 1)
+ stepx = 1;
+
+ if (stepy < 1)
+ stepy = 1;
+ }
+
+ if (hint.flags & PAspect)
+ {
+ if (hint.min_aspect.y > 0)
+ mina = ((double)hint.min_aspect.x) / ((double)hint.min_aspect.y);
+
+ if (hint.max_aspect.y > 0)
+ maxa = ((double)hint.max_aspect.x) / ((double)hint.max_aspect.y);
+ }
+
+ if (min_w)
+ *min_w = minw;
+
+ if (min_h)
+ *min_h = minh;
+
+ if (max_w)
+ *max_w = maxw;
+
+ if (max_h)
+ *max_h = maxh;
+
+ if (base_w)
+ *base_w = basew;
+
+ if (base_h)
+ *base_h = baseh;
+
+ if (step_x)
+ *step_x = stepx;
+
+ if (step_y)
+ *step_y = stepy;
+
+ if (min_aspect)
+ *min_aspect = mina;
+
+ if (max_aspect)
+ *max_aspect = maxa;
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_icccm_title_set(Ecore_X_Window win,
+ const char *t)
+{
+ char *list[1];
+ XTextProperty xprop;
+ int ret;
+
+ if (!t)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xprop.value = NULL;
+#ifdef X_HAVE_UTF8_STRING
+ list[0] = strdup(t);
+ ret =
+ Xutf8TextListToTextProperty(_ecore_x_disp, list, 1, XUTF8StringStyle,
+ &xprop);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ list[0] = strdup(t);
+ ret =
+ XmbTextListToTextProperty(_ecore_x_disp, list, 1, XStdICCTextStyle,
+ &xprop);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ if (ret >= Success)
+ {
+ XSetWMName(_ecore_x_disp, win, &xprop);
+ if (xprop.value)
+ XFree(xprop.value);
+ }
+ else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
+ {
+ XSetWMName(_ecore_x_disp, win, &xprop);
+ if (xprop.value)
+ XFree(xprop.value);
+ }
+
+ free(list[0]);
+}
+
+EAPI char *
+ecore_x_icccm_title_get(Ecore_X_Window win)
+{
+ XTextProperty xprop;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xprop.value = NULL;
+ if (XGetWMName(_ecore_x_disp, win, &xprop) >= Success)
+ {
+ if (xprop.value)
+ {
+ char **list = NULL;
+ char *t = NULL;
+ int num = 0;
+ int ret;
+
+ if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
+ t = strdup((char *)xprop.value);
+ else
+ {
+ /* convert to utf8 */
+#ifdef X_HAVE_UTF8_STRING
+ ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
+ &list, &num);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
+ &list, &num);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+
+ if ((ret == XLocaleNotSupported) ||
+ (ret == XNoMemory) || (ret == XConverterNotFound))
+ t = strdup((char *)xprop.value);
+ else if ((ret >= Success) && (num > 0))
+ t = strdup(list[0]);
+
+ if (list)
+ XFreeStringList(list);
+ }
+
+ if (xprop.value)
+ XFree(xprop.value);
+
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Set protocol atoms explicitly
+ * @param win The Window
+ * @param protos An array of protocol atoms
+ * @param num the number of members of the array
+ */
+EAPI void
+ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,
+ Ecore_X_Atom *protos,
+ int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num > 0)
+ XSetWMProtocols(_ecore_x_disp, win, (Atom *)(protos), num);
+ else
+ XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_PROTOCOLS);
+}
+
+/**
+ * Set or unset a wm protocol property.
+ * @param win The Window
+ * @param protocol The protocol to enable/disable
+ * @param on On/Off
+ */
+EAPI void
+ecore_x_icccm_protocol_set(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol,
+ Eina_Bool on)
+{
+ Atom *protos = NULL;
+ Atom proto;
+ int protos_count = 0;
+ int already_set = 0;
+ int i;
+
+ /* Check for invalid values */
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ proto = _ecore_x_atoms_wm_protocols[protocol];
+
+ if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
+ {
+ protos = NULL;
+ protos_count = 0;
+ }
+
+ for (i = 0; i < protos_count; i++)
+ {
+ if (protos[i] == proto)
+ {
+ already_set = 1;
+ break;
+ }
+ }
+
+ if (on)
+ {
+ Atom *new_protos = NULL;
+
+ if (already_set)
+ goto leave;
+
+ new_protos = malloc((protos_count + 1) * sizeof(Atom));
+ if (!new_protos)
+ goto leave;
+
+ for (i = 0; i < protos_count; i++)
+ new_protos[i] = protos[i];
+ new_protos[protos_count] = proto;
+ XSetWMProtocols(_ecore_x_disp, win, new_protos, protos_count + 1);
+ free(new_protos);
+ }
+ else
+ {
+ if (!already_set)
+ goto leave;
+
+ for (i = 0; i < protos_count; i++)
+ {
+ if (protos[i] == proto)
+ {
+ int j;
+
+ for (j = i + 1; j < protos_count; j++)
+ protos[j - 1] = protos[j];
+ if (protos_count > 1)
+ XSetWMProtocols(_ecore_x_disp, win, protos,
+ protos_count - 1);
+ else
+ XDeleteProperty(_ecore_x_disp, win,
+ ECORE_X_ATOM_WM_PROTOCOLS);
+
+ goto leave;
+ }
+ }
+ }
+
+leave:
+ if (protos)
+ XFree(protos);
+}
+
+/**
+ * Determines whether a protocol is set for a window.
+ * @param win The Window
+ * @param protocol The protocol to query
+ * @return 1 if the protocol is set, else 0.
+ */
+EAPI Eina_Bool
+ecore_x_icccm_protocol_isset(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol)
+{
+ Atom proto, *protos = NULL;
+ int i, protos_count = 0;
+ Eina_Bool ret = EINA_FALSE;
+
+ /* check for invalid values */
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ proto = _ecore_x_atoms_wm_protocols[protocol];
+
+ if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
+ return EINA_FALSE;
+
+ for (i = 0; i < protos_count; i++)
+ if (protos[i] == proto)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+
+ if (protos)
+ XFree(protos);
+
+ return ret;
+}
+
+/**
+ * Set a window name & class.
+ * @param win The window
+ * @param n The name string
+ * @param c The class string
+ *
+ * Set a window name * class
+ */
+EAPI void
+ecore_x_icccm_name_class_set(Ecore_X_Window win,
+ const char *n,
+ const char *c)
+{
+ XClassHint *xch;
+
+ xch = XAllocClassHint();
+ if (!xch)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xch->res_name = (char *)n;
+ xch->res_class = (char *)c;
+ XSetClassHint(_ecore_x_disp, win, xch);
+ XFree(xch);
+}
+
+/**
+ * Get a window name & class.
+ * @param win The window
+ * @param n The name string
+ * @param c The class string
+ *
+ * Get a window name * class
+ */
+EAPI void
+ecore_x_icccm_name_class_get(Ecore_X_Window win,
+ char **n,
+ char **c)
+{
+ XClassHint xch;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (n)
+ *n = NULL;
+
+ if (c)
+ *c = NULL;
+
+ xch.res_name = NULL;
+ xch.res_class = NULL;
+ if (XGetClassHint(_ecore_x_disp, win, &xch))
+ {
+ if (n)
+ if (xch.res_name)
+ *n = strdup(xch.res_name);
+
+ if (c)
+ if (xch.res_class)
+ *c = strdup(xch.res_class);
+
+ XFree(xch.res_name);
+ XFree(xch.res_class);
+ }
+}
+
+/**
+ * Get a window client machine string.
+ * @param win The window
+ * @return The windows client machine string
+ *
+ * Return the client machine of a window. String must be free'd when done with.
+ */
+EAPI char *
+ecore_x_icccm_client_machine_get(Ecore_X_Window win)
+{
+ char *name;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_CLIENT_MACHINE);
+ return name;
+}
+
+/**
+ * Sets the WM_COMMAND property for @a win.
+ *
+ * @param win The window.
+ * @param argc Number of arguments.
+ * @param argv Arguments.
+ */
+EAPI void
+ecore_x_icccm_command_set(Ecore_X_Window win,
+ int argc,
+ char **argv)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSetCommand(_ecore_x_disp, win, argv, argc);
+}
+
+/**
+ * Get the WM_COMMAND property for @a win.
+ *
+ * Return the command of a window. String must be free'd when done with.
+ *
+ * @param win The window.
+ * @param argc Number of arguments.
+ * @param argv Arguments.
+ */
+EAPI void
+ecore_x_icccm_command_get(Ecore_X_Window win,
+ int *argc,
+ char ***argv)
+{
+ int i, c;
+ char **v;
+
+ if (argc)
+ *argc = 0;
+
+ if (argv)
+ *argv = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetCommand(_ecore_x_disp, win, &v, &c))
+ return;
+
+ if (c < 1)
+ {
+ if (v)
+ XFreeStringList(v);
+
+ return;
+ }
+
+ if (argc)
+ *argc = c;
+
+ if (argv)
+ {
+ (*argv) = malloc(c * sizeof(char *));
+ if (!*argv)
+ {
+ XFreeStringList(v);
+ if (argc)
+ *argc = 0;
+
+ return;
+ }
+
+ for (i = 0; i < c; i++)
+ {
+ if (v[i])
+ (*argv)[i] = strdup(v[i]);
+ else
+ (*argv)[i] = strdup("");
+ }
+ }
+
+ XFreeStringList(v);
+}
+
+/**
+ * Set a window icon name.
+ * @param win The window
+ * @param t The icon name string
+ *
+ * Set a window icon name
+ */
+EAPI void
+ecore_x_icccm_icon_name_set(Ecore_X_Window win,
+ const char *t)
+{
+ char *list[1];
+ XTextProperty xprop;
+ int ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xprop.value = NULL;
+#ifdef X_HAVE_UTF8_STRING
+ list[0] = strdup(t);
+ ret = Xutf8TextListToTextProperty(_ecore_x_disp, list, 1,
+ XUTF8StringStyle, &xprop);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ list[0] = strdup(t);
+ ret = XmbTextListToTextProperty(_ecore_x_disp, list, 1,
+ XStdICCTextStyle, &xprop);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ if (ret >= Success)
+ {
+ XSetWMIconName(_ecore_x_disp, win, &xprop);
+ if (xprop.value)
+ XFree(xprop.value);
+ }
+ else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
+ {
+ XSetWMIconName(_ecore_x_disp, win, &xprop);
+ if (xprop.value)
+ XFree(xprop.value);
+ }
+
+ free(list[0]);
+}
+
+/**
+ * Get a window icon name.
+ * @param win The window
+ * @return The windows icon name string
+ *
+ * Return the icon name of a window. String must be free'd when done with.
+ */
+EAPI char *
+ecore_x_icccm_icon_name_get(Ecore_X_Window win)
+{
+ XTextProperty xprop;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xprop.value = NULL;
+ if (XGetWMIconName(_ecore_x_disp, win, &xprop) >= Success)
+ {
+ if (xprop.value)
+ {
+ char **list = NULL;
+ char *t = NULL;
+ int num = 0;
+ int ret;
+
+ if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
+ t = strdup((char *)xprop.value);
+ else
+ {
+ /* convert to utf8 */
+#ifdef X_HAVE_UTF8_STRING
+ ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
+ &list, &num);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
+ &list, &num);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+
+ if ((ret == XLocaleNotSupported) ||
+ (ret == XNoMemory) || (ret == XConverterNotFound))
+ t = strdup((char *)xprop.value);
+ else if (ret >= Success)
+ {
+ if ((num >= 1) && (list))
+ t = strdup(list[0]);
+
+ if (list)
+ XFreeStringList(list);
+ }
+ }
+
+ if (xprop.value)
+ XFree(xprop.value);
+
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Add a subwindow to the list of windows that need a different colormap installed.
+ * @param win The toplevel window
+ * @param subwin The subwindow to be added to the colormap windows list
+ */
+EAPI void
+ecore_x_icccm_colormap_window_set(Ecore_X_Window win,
+ Ecore_X_Window subwin)
+{
+ int num = 0, i;
+ unsigned char *old_data = NULL;
+ unsigned char *data = NULL;
+ Window *oldset = NULL;
+ Window *newset = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win,
+ ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ XA_WINDOW, 32, &old_data, &num))
+ {
+ newset = calloc(1, sizeof(Window));
+ if (!newset)
+ return;
+
+ newset[0] = subwin;
+ num = 1;
+ data = (unsigned char *)newset;
+ }
+ else
+ {
+ newset = calloc(num + 1, sizeof(Window));
+ oldset = (Window *)old_data;
+ if (!newset)
+ return;
+
+ for (i = 0; i < num; ++i)
+ {
+ if (oldset[i] == subwin)
+ {
+ if (old_data)
+ XFree(old_data);
+
+ old_data = NULL;
+ free(newset);
+ return;
+ }
+
+ newset[i] = oldset[i];
+ }
+
+ newset[num++] = subwin;
+ if (old_data)
+ XFree(old_data);
+
+ data = (unsigned char *)newset;
+ }
+
+ ecore_x_window_prop_property_set(win,
+ ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ XA_WINDOW, 32, data, num);
+ free(newset);
+}
+
+/**
+ * Remove a window from the list of colormap windows.
+ * @param win The toplevel window
+ * @param subwin The window to be removed from the colormap window list.
+ */
+EAPI void
+ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,
+ Ecore_X_Window subwin)
+{
+ int num = 0, i, j, k = 0;
+ unsigned char *old_data = NULL;
+ unsigned char *data = NULL;
+ Window *oldset = NULL;
+ Window *newset = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_prop_property_get(win,
+ ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ XA_WINDOW, 32, &old_data, &num))
+ return;
+
+ oldset = (Window *)old_data;
+ for (i = 0; i < num; i++)
+ {
+ if (oldset[i] == subwin)
+ {
+ if (num == 1)
+ {
+ XDeleteProperty(_ecore_x_disp,
+ win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS);
+ if (old_data)
+ XFree(old_data);
+
+ old_data = NULL;
+ return;
+ }
+ else
+ {
+ newset = calloc(num - 1, sizeof(Window));
+ data = (unsigned char *)newset;
+ for (j = 0; j < num; ++j)
+ if (oldset[j] != subwin)
+ newset[k++] = oldset[j];
+
+ ecore_x_window_prop_property_set(
+ win,
+ ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
+ XA_WINDOW,
+ 32,
+ data,
+ k);
+ if (old_data)
+ XFree(old_data);
+
+ old_data = NULL;
+ free(newset);
+ return;
+ }
+ }
+ }
+
+ if (old_data)
+ XFree(old_data);
+}
+
+/**
+ * Specify that a window is transient for another top-level window and should be handled accordingly.
+ * @param win the transient window
+ * @param forwin the toplevel window
+ */
+EAPI void
+ecore_x_icccm_transient_for_set(Ecore_X_Window win,
+ Ecore_X_Window forwin)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSetTransientForHint(_ecore_x_disp, win, forwin);
+}
+
+/**
+ * Remove the transient_for setting from a window.
+ * @param win The window
+ */
+EAPI void
+ecore_x_icccm_transient_for_unset(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_TRANSIENT_FOR);
+}
+
+/**
+ * Get the window this window is transient for, if any.
+ * @param win The window to check
+ * @return The window ID of the top-level window, or 0 if the property does not exist.
+ */
+EAPI Ecore_X_Window
+ecore_x_icccm_transient_for_get(Ecore_X_Window win)
+{
+ Window forwin;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XGetTransientForHint(_ecore_x_disp, win, &forwin))
+ return (Ecore_X_Window)forwin;
+ else
+ return 0;
+}
+
+/**
+ * Set the window role hint.
+ * @param win The window
+ * @param role The role string
+ */
+EAPI void
+ecore_x_icccm_window_role_set(Ecore_X_Window win,
+ const char *role)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE,
+ (char *)role);
+}
+
+/**
+ * Get the window role.
+ * @param win The window
+ * @return The window's role string.
+ */
+EAPI char *
+ecore_x_icccm_window_role_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE);
+}
+
+/**
+ * Set the window's client leader.
+ * @param win The window
+ * @param l The client leader window
+ *
+ * All non-transient top-level windows created by an app other than
+ * the main window must have this property set to the app's main window.
+ */
+EAPI void
+ecore_x_icccm_client_leader_set(Ecore_X_Window win,
+ Ecore_X_Window l)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
+ &l, 1);
+}
+
+/**
+ * Get the window's client leader.
+ * @param win The window
+ * @return The window's client leader window, or 0 if unset */
+EAPI Ecore_X_Window
+ecore_x_icccm_client_leader_get(Ecore_X_Window win)
+{
+ Ecore_X_Window l;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
+ &l, 1) > 0)
+ return l;
+
+ return 0;
+}
+
+EAPI void
+ecore_x_icccm_iconic_request_send(Ecore_X_Window win,
+ Ecore_X_Window root)
+{
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.format = 32;
+ xev.xclient.message_type = ECORE_X_ATOM_WM_CHANGE_STATE;
+ xev.xclient.data.l[0] = IconicState;
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+}
+
+/* FIXME: there are older E hints, gnome hints and mwm hints and new netwm */
+/* hints. each should go in their own file/section so we know which */
+/* is which. also older kde hints too. we should try support as much */
+/* as makese sense to support */
diff --git a/src/lib/ecore_x/xlib/ecore_x_image.c b/src/lib/ecore_x/xlib/ecore_x_image.c
new file mode 100644
index 0000000000..def81104a2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_image.c
@@ -0,0 +1,626 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+#include <X11/extensions/XShm.h>
+#include <X11/Xutil.h>
+
+static int _ecore_x_image_shm_can = -1;
+static int _ecore_x_image_err = 0;
+
+static int
+_ecore_x_image_error_handler(Display *d EINA_UNUSED,
+ XErrorEvent *ev EINA_UNUSED)
+{
+ _ecore_x_image_err = 1;
+ return 0;
+}
+
+static void
+_ecore_x_image_shm_check(void)
+{
+ XErrorHandler ph;
+ XShmSegmentInfo shminfo;
+ XImage *xim;
+
+ if (_ecore_x_image_shm_can != -1)
+ return;
+
+ XSync(_ecore_x_disp, False);
+ _ecore_x_image_err = 0;
+
+ xim = XShmCreateImage(_ecore_x_disp,
+ DefaultVisual(_ecore_x_disp,
+ DefaultScreen(_ecore_x_disp)),
+ DefaultDepth(_ecore_x_disp,
+ DefaultScreen(_ecore_x_disp)),
+ ZPixmap, NULL,
+ &shminfo, 1, 1);
+ if (!xim)
+ {
+ _ecore_x_image_shm_can = 0;
+ return;
+ }
+
+ shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height,
+ IPC_CREAT | 0666);
+ if (shminfo.shmid == -1)
+ {
+ XDestroyImage(xim);
+ _ecore_x_image_shm_can = 0;
+ return;
+ }
+
+ shminfo.readOnly = False;
+ shminfo.shmaddr = shmat(shminfo.shmid, 0, 0);
+ xim->data = shminfo.shmaddr;
+
+ if (xim->data == (char *)-1)
+ {
+ XDestroyImage(xim);
+ _ecore_x_image_shm_can = 0;
+ return;
+ }
+
+ ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
+ XShmAttach(_ecore_x_disp, &shminfo);
+ XShmGetImage(_ecore_x_disp, DefaultRootWindow(_ecore_x_disp),
+ xim, 0, 0, 0xffffffff);
+ XSync(_ecore_x_disp, False);
+ XSetErrorHandler((XErrorHandler)ph);
+ if (_ecore_x_image_err)
+ {
+ XShmDetach(_ecore_x_disp, &shminfo);
+ XDestroyImage(xim);
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+ _ecore_x_image_shm_can = 0;
+ return;
+ }
+
+ XShmDetach(_ecore_x_disp, &shminfo);
+ XDestroyImage(xim);
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+
+ _ecore_x_image_shm_can = 1;
+}
+
+struct _Ecore_X_Image
+{
+ XShmSegmentInfo shminfo;
+ Ecore_X_Visual vis;
+ XImage *xim;
+ int depth;
+ int w, h;
+ int bpl, bpp, rows;
+ unsigned char *data;
+ Eina_Bool shm : 1;
+};
+
+EAPI Ecore_X_Image *
+ecore_x_image_new(int w,
+ int h,
+ Ecore_X_Visual vis,
+ int depth)
+{
+ Ecore_X_Image *im;
+
+ im = calloc(1, sizeof(Ecore_X_Image));
+ if (!im)
+ return NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ im->w = w;
+ im->h = h;
+ im->vis = vis;
+ im->depth = depth;
+ _ecore_x_image_shm_check();
+ im->shm = _ecore_x_image_shm_can;
+ return im;
+}
+
+EAPI void
+ecore_x_image_free(Ecore_X_Image *im)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (im->shm)
+ {
+ if (im->xim)
+ {
+ XShmDetach(_ecore_x_disp, &(im->shminfo));
+ XDestroyImage(im->xim);
+ shmdt(im->shminfo.shmaddr);
+ shmctl(im->shminfo.shmid, IPC_RMID, 0);
+ }
+ }
+ else if (im->xim)
+ {
+ free(im->xim->data);
+ im->xim->data = NULL;
+ XDestroyImage(im->xim);
+ }
+
+ free(im);
+}
+
+static void
+_ecore_x_image_shm_create(Ecore_X_Image *im)
+{
+ im->xim = XShmCreateImage(_ecore_x_disp, im->vis, im->depth,
+ ZPixmap, NULL, &(im->shminfo),
+ im->w, im->h);
+ if (!im->xim)
+ return;
+
+ im->shminfo.shmid = shmget(IPC_PRIVATE,
+ im->xim->bytes_per_line * im->xim->height,
+ IPC_CREAT | 0666);
+ if (im->shminfo.shmid == -1)
+ {
+ XDestroyImage(im->xim);
+ return;
+ }
+
+ im->shminfo.readOnly = False;
+ im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0);
+ im->xim->data = im->shminfo.shmaddr;
+ if ((im->xim->data == (char *)-1) ||
+ (!im->xim->data))
+ {
+ shmdt(im->shminfo.shmaddr);
+ shmctl(im->shminfo.shmid, IPC_RMID, 0);
+ XDestroyImage(im->xim);
+ return;
+ }
+
+ XShmAttach(_ecore_x_disp, &im->shminfo);
+
+ im->data = (unsigned char *)im->xim->data;
+
+ im->bpl = im->xim->bytes_per_line;
+ im->rows = im->xim->height;
+ if (im->xim->bits_per_pixel <= 8)
+ im->bpp = 1;
+ else if (im->xim->bits_per_pixel <= 16)
+ im->bpp = 2;
+ else
+ im->bpp = 4;
+}
+
+EAPI Eina_Bool
+ecore_x_image_get(Ecore_X_Image *im,
+ Ecore_X_Drawable draw,
+ int x,
+ int y,
+ int sx,
+ int sy,
+ int w,
+ int h)
+{
+ Eina_Bool ret = EINA_TRUE;
+ XErrorHandler ph;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (im->shm)
+ {
+ if (!im->xim)
+ _ecore_x_image_shm_create(im);
+
+ if (!im->xim)
+ return 0;
+
+ _ecore_x_image_err = 0;
+ // optimised path
+ ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler);
+ if ((sx == 0) && (w == im->w))
+ {
+ im->xim->data = (char *)
+ im->data + (im->xim->bytes_per_line * sy) + (sx * im->bpp);
+ im->xim->width = w;
+ im->xim->height = h;
+ XGrabServer(_ecore_x_disp);
+ if (!XShmGetImage(_ecore_x_disp, draw, im->xim, x, y, 0xffffffff))
+ ret = EINA_FALSE;
+ XUngrabServer(_ecore_x_disp);
+ ecore_x_sync();
+ }
+ // unavoidable thanks to mit-shm get api - tmp shm buf + copy into it
+ else
+ {
+ Ecore_X_Image *tim;
+ unsigned char *spixels, *sp, *pixels, *p;
+ int bpp, bpl, rows, sbpp, sbpl, srows;
+ int r;
+
+ tim = ecore_x_image_new(w, h, im->vis, im->depth);
+ if (tim)
+ {
+ ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h);
+ if (ret)
+ {
+ spixels = ecore_x_image_data_get(tim,
+ &sbpl,
+ &srows,
+ &sbpp);
+ pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp);
+ if ((pixels) && (spixels))
+ {
+ p = pixels + (sy * bpl) + (sx * bpp);
+ sp = spixels;
+ for (r = srows; r > 0; r--)
+ {
+ memcpy(p, sp, sbpl);
+ p += bpl;
+ sp += sbpl;
+ }
+ }
+ }
+
+ ecore_x_image_free(tim);
+ }
+ }
+
+ XSetErrorHandler((XErrorHandler)ph);
+ if (_ecore_x_image_err)
+ ret = EINA_FALSE;
+ }
+ else
+ {
+ printf("currently unimplemented ecore_x_image_get without shm\n");
+ ret = EINA_FALSE;
+ }
+
+ return ret;
+}
+
+EAPI void
+ecore_x_image_put(Ecore_X_Image *im,
+ Ecore_X_Drawable draw,
+ Ecore_X_GC gc,
+ int x,
+ int y,
+ int sx,
+ int sy,
+ int w,
+ int h)
+{
+ Ecore_X_GC tgc = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!gc)
+ {
+ XGCValues gcv;
+ memset(&gcv, 0, sizeof(gcv));
+ gcv.subwindow_mode = IncludeInferiors;
+ tgc = XCreateGC(_ecore_x_disp, draw, GCSubwindowMode, &gcv);
+ gc = tgc;
+ }
+ if (!im->xim) _ecore_x_image_shm_create(im);
+ if (im->xim)
+ XShmPutImage(_ecore_x_disp, draw, gc, im->xim, sx, sy, x, y, w, h, False);
+ if (tgc) ecore_x_gc_free(tgc);
+}
+
+EAPI void *
+ecore_x_image_data_get(Ecore_X_Image *im,
+ int *bpl,
+ int *rows,
+ int *bpp)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!im->xim) _ecore_x_image_shm_create(im);
+ if (!im->xim) return NULL;
+ if (bpl) *bpl = im->bpl;
+ if (rows) *rows = im->rows;
+ if (bpp) *bpp = im->bpp;
+ return im->data;
+}
+
+EAPI Eina_Bool
+ecore_x_image_is_argb32_get(Ecore_X_Image *im)
+{
+ Visual *vis = im->vis;
+ if (!im->xim) _ecore_x_image_shm_create(im);
+ if (((vis->class == TrueColor) ||
+ (vis->class == DirectColor)) &&
+ (im->depth >= 24) &&
+ (vis->red_mask == 0xff0000) &&
+ (vis->green_mask == 0x00ff00) &&
+ (vis->blue_mask == 0x0000ff))
+ {
+#ifdef WORDS_BIGENDIAN
+ if (im->xim->bitmap_bit_order == MSBFirst) return EINA_TRUE;
+#else
+ if (im->xim->bitmap_bit_order == LSBFirst) return EINA_TRUE;
+#endif
+ }
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_image_to_argb_convert(void *src,
+ int sbpp,
+ int sbpl,
+ Ecore_X_Colormap c,
+ Ecore_X_Visual v,
+ int x,
+ int y,
+ int w,
+ int h,
+ unsigned int *dst,
+ int dbpl,
+ int dx,
+ int dy)
+{
+ Visual *vis = v;
+ XColor *cols = NULL;
+ int n = 0, nret = 0, i, row;
+ unsigned int pal[256], r, g, b;
+ enum
+ {
+ rgbnone = 0,
+ rgb565,
+ bgr565,
+ rgbx555,
+ argbx888,
+ abgrx888,
+ rgba888x,
+ bgra888x,
+ argbx666
+ };
+ int mode = 0;
+
+ sbpp *= 8;
+
+ n = vis->map_entries;
+ if ((n <= 256) &&
+ ((vis->class == PseudoColor) ||
+ (vis->class == StaticColor) ||
+ (vis->class == GrayScale) ||
+ (vis->class == StaticGray)))
+ {
+ if (!c)
+ c = DefaultColormap(_ecore_x_disp,
+ DefaultScreen(_ecore_x_disp));
+ cols = alloca(n * sizeof(XColor));
+ for (i = 0; i < n; i++)
+ {
+ cols[i].pixel = i;
+ cols[i].flags = DoRed | DoGreen | DoBlue;
+ cols[i].red = 0;
+ cols[i].green = 0;
+ cols[i].blue = 0;
+ }
+ XQueryColors(_ecore_x_disp, c, cols, n);
+ for (i = 0; i < n; i++)
+ {
+ pal[i] = 0xff000000 |
+ ((cols[i].red >> 8) << 16) |
+ ((cols[i].green >> 8) << 8) |
+ ((cols[i].blue >> 8));
+ }
+ nret = n;
+ }
+ else if ((vis->class == TrueColor) ||
+ (vis->class == DirectColor))
+ {
+ if ((vis->red_mask == 0x00ff0000) &&
+ (vis->green_mask == 0x0000ff00) &&
+ (vis->blue_mask == 0x000000ff))
+ mode = argbx888;
+ else if ((vis->red_mask == 0x000000ff) &&
+ (vis->green_mask == 0x0000ff00) &&
+ (vis->blue_mask == 0x00ff0000))
+ mode = abgrx888;
+ else if ((vis->red_mask == 0xff000000) &&
+ (vis->green_mask == 0x00ff0000) &&
+ (vis->blue_mask == 0x0000ff00))
+ mode = rgba888x;
+ else if ((vis->red_mask == 0x0000ff00) &&
+ (vis->green_mask == 0x00ff0000) &&
+ (vis->blue_mask == 0xff000000))
+ mode = bgra888x;
+ else if ((vis->red_mask == 0x0003f000) &&
+ (vis->green_mask == 0x00000fc0) &&
+ (vis->blue_mask == 0x0000003f))
+ mode = argbx666;
+ else if ((vis->red_mask == 0x0000f800) &&
+ (vis->green_mask == 0x000007e0) &&
+ (vis->blue_mask == 0x0000001f))
+ mode = rgb565;
+ else if ((vis->red_mask == 0x0000001f) &&
+ (vis->green_mask == 0x000007e0) &&
+ (vis->blue_mask == 0x0000f800))
+ mode = bgr565;
+ else if ((vis->red_mask == 0x00007c00) &&
+ (vis->green_mask == 0x000003e0) &&
+ (vis->blue_mask == 0x0000001f))
+ mode = rgbx555;
+ else
+ return EINA_FALSE;
+ }
+ for (row = 0; row < h; row++)
+ {
+ unsigned char *s8;
+ unsigned short *s16;
+ unsigned int *s32;
+ unsigned int *dp, *de;
+
+ dp = ((unsigned int *)(((unsigned char *)dst) +
+ ((dy + row) * dbpl))) + dx;
+ de = dp + w;
+ switch (sbpp)
+ {
+ case 8:
+ s8 = ((unsigned char *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
+ if (nret > 0)
+ {
+ while (dp < de)
+ {
+ *dp = pal[*s8];
+ s8++; dp++;
+ }
+ }
+ else
+ return EINA_FALSE;
+ break;
+
+ case 16:
+ s16 = ((unsigned short *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
+ switch (mode)
+ {
+ case rgb565:
+ while (dp < de)
+ {
+ r = (*s16 & 0xf800) << 8;
+ g = (*s16 & 0x07e0) << 5;
+ b = (*s16 & 0x001f) << 3;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ case bgr565:
+ while (dp < de)
+ {
+ r = (*s16 & 0x001f) << 19;
+ g = (*s16 & 0x07e0) << 5;
+ b = (*s16 & 0xf800) >> 8;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ case rgbx555:
+ while (dp < de)
+ {
+ r = (*s16 & 0x7c00) << 9;
+ g = (*s16 & 0x03e0) << 6;
+ b = (*s16 & 0x001f) << 3;
+ r |= (r >> 5) & 0xff0000;
+ g |= (g >> 5) & 0x00ff00;
+ b |= (b >> 5);
+ *dp = 0xff000000 | r | g | b;
+ s16++; dp++;
+ }
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ break;
+
+ case 24:
+ case 32:
+ s32 = ((unsigned int *)(((unsigned char *)src) + ((y + row) * sbpl))) + x;
+ switch (mode)
+ {
+ case argbx888:
+ while (dp < de)
+ {
+ *dp = 0xff000000 | *s32;
+ s32++; dp++;
+ }
+ break;
+
+ case abgrx888:
+ while (dp < de)
+ {
+ r = *s32 & 0x000000ff;
+ g = *s32 & 0x0000ff00;
+ b = *s32 & 0x00ff0000;
+ *dp = 0xff000000 | (r << 16) | (g) | (b >> 16);
+ s32++; dp++;
+ }
+ break;
+
+ case rgba888x:
+ while (dp < de)
+ {
+ *dp = 0xff000000 | (*s32 >> 8);
+ s32++; dp++;
+ }
+ break;
+
+ case bgra888x:
+ while (dp < de)
+ {
+ r = *s32 & 0x0000ff00;
+ g = *s32 & 0x00ff0000;
+ b = *s32 & 0xff000000;
+ *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24);
+ s32++; dp++;
+ }
+ break;
+
+ case argbx666:
+ while (dp < de)
+ {
+ r = (*s32 & 0x3f000) << 6;
+ g = (*s32 & 0x00fc0) << 4;
+ b = (*s32 & 0x0003f) << 2;
+ r |= (r >> 6) & 0xff0000;
+ g |= (g >> 6) & 0x00ff00;
+ b |= (b >> 6);
+ *dp = 0xff000000 | r | g | b;
+ s32++; dp++;
+ }
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ break;
+ break;
+
+ default:
+ return EINA_FALSE;
+ break;
+ }
+ }
+ return EINA_TRUE;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_mwm.c b/src/lib/ecore_x/xlib/ecore_x_mwm.c
new file mode 100644
index 0000000000..7812cc23ae
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_mwm.c
@@ -0,0 +1,106 @@
+/*
+ * Various MWM related functions.
+ *
+ * This is ALL the code involving anything MWM related. for both WM and
+ * client.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+#define ECORE_X_MWM_HINTS_FUNCTIONS (1 << 0)
+#define ECORE_X_MWM_HINTS_DECORATIONS (1 << 1)
+#define ECORE_X_MWM_HINTS_INPUT_MODE (1 << 2)
+#define ECORE_X_MWM_HINTS_STATUS (1 << 3)
+
+typedef struct _mwmhints
+{
+ CARD32 flags;
+ CARD32 functions;
+ CARD32 decorations;
+ INT32 inputmode;
+ CARD32 status;
+}
+MWMHints;
+
+EAPI Eina_Bool
+ecore_x_mwm_hints_get(Ecore_X_Window win,
+ Ecore_X_MWM_Hint_Func *fhint,
+ Ecore_X_MWM_Hint_Decor *dhint,
+ Ecore_X_MWM_Hint_Input *ihint)
+{
+ unsigned char *p = NULL;
+ MWMHints *mwmhints = NULL;
+ int num;
+ Eina_Bool ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = EINA_FALSE;
+ if (!ecore_x_window_prop_property_get(win,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ 32, &p, &num))
+ return EINA_FALSE;
+
+ mwmhints = (MWMHints *)p;
+ if (mwmhints)
+ {
+ if (num >= 4)
+ {
+ if (dhint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_DECORATIONS)
+ *dhint = mwmhints->decorations;
+ else
+ *dhint = ECORE_X_MWM_HINT_DECOR_ALL;
+ }
+
+ if (fhint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_FUNCTIONS)
+ *fhint = mwmhints->functions;
+ else
+ *fhint = ECORE_X_MWM_HINT_FUNC_ALL;
+ }
+
+ if (ihint)
+ {
+ if (mwmhints->flags & ECORE_X_MWM_HINTS_INPUT_MODE)
+ *ihint = mwmhints->inputmode;
+ else
+ *ihint = ECORE_X_MWM_HINT_INPUT_MODELESS;
+ }
+
+ ret = EINA_TRUE;
+ }
+
+ free(mwmhints);
+ }
+
+ return ret;
+}
+
+EAPI void
+ecore_x_mwm_borderless_set(Ecore_X_Window win,
+ Eina_Bool borderless)
+{
+ unsigned int data[5] = {0, 0, 0, 0, 0};
+
+ data[0] = 2; /* just set the decorations hint! */
+ data[2] = !borderless;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_property_set(win,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ ECORE_X_ATOM_MOTIF_WM_HINTS,
+ 32, (void *)data, 5);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_netwm.c b/src/lib/ecore_x/xlib/ecore_x_netwm.c
new file mode 100644
index 0000000000..3f08af8b9c
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_netwm.c
@@ -0,0 +1,2083 @@
+/*
+ * _NET_WM... aka Extended Window Manager Hint (EWMH) functions.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+typedef struct _Ecore_X_Startup_Info Ecore_X_Startup_Info;
+
+struct _Ecore_X_Startup_Info
+{
+ Ecore_X_Window win;
+
+ int init;
+
+ int buffer_size;
+ char *buffer;
+
+ int length;
+
+ /* These are the sequence info fields */
+ char *id;
+ char *name;
+ int screen;
+ char *bin;
+ char *icon;
+ int desktop;
+ int timestamp;
+ char *description;
+ char *wmclass;
+ int silent;
+};
+
+static void _ecore_x_window_prop_string_utf8_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ const char *str);
+static char *_ecore_x_window_prop_string_utf8_get(Ecore_X_Window win,
+ Ecore_X_Atom atom);
+#if 0 /* Unused */
+static int _ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info);
+static int _ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info,
+ char *data);
+#endif /* if 0 */
+static void _ecore_x_netwm_startup_info_free(void *data);
+
+/*
+ * Convenience macros
+ */
+#define _ATOM_SET_UTF8_STRING_LIST(win, atom, string, cnt) \
+ XChangeProperty(_ecore_x_disp, \
+ win, \
+ atom, \
+ ECORE_X_ATOM_UTF8_STRING, \
+ 8, \
+ PropModeReplace, \
+ (unsigned char *)string, \
+ cnt)
+
+/*
+ * Local variables
+ */
+
+static Eina_Hash *startup_info = NULL;
+
+EAPI void
+ecore_x_netwm_init(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ startup_info = eina_hash_string_superfast_new(
+ _ecore_x_netwm_startup_info_free);
+}
+
+EAPI void
+ecore_x_netwm_shutdown(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (startup_info)
+ eina_hash_free(startup_info);
+
+ startup_info = NULL;
+}
+
+/*
+ * WM identification
+ */
+EAPI void
+ecore_x_netwm_wm_identify(Ecore_X_Window root,
+ Ecore_X_Window check,
+ const char *wm_name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(check,
+ ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
+ &check,
+ 1);
+ _ecore_x_window_prop_string_utf8_set(check,
+ ECORE_X_ATOM_NET_WM_NAME,
+ wm_name);
+ /* This one isn't mandatory */
+ _ecore_x_window_prop_string_utf8_set(root,
+ ECORE_X_ATOM_NET_WM_NAME,
+ wm_name);
+ ecore_x_window_prop_window_set(root,
+ ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
+ &check,
+ 1);
+}
+
+/*
+ * Set supported atoms
+ */
+EAPI void
+ecore_x_netwm_supported_set(Ecore_X_Window root,
+ Ecore_X_Atom *supported,
+ int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_atom_set(root,
+ ECORE_X_ATOM_NET_SUPPORTED,
+ supported,
+ num);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_supported_get(Ecore_X_Window root,
+ Ecore_X_Atom **supported,
+ int *num)
+{
+ int num_ret;
+
+ if (num)
+ *num = 0;
+
+ if (supported)
+ *supported = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ num_ret = ecore_x_window_prop_atom_list_get(root, ECORE_X_ATOM_NET_SUPPORTED,
+ supported);
+ if (num_ret <= 0)
+ return EINA_FALSE;
+
+ if (num)
+ *num = num_ret;
+
+ return EINA_TRUE;
+}
+
+/*
+ * Desktop configuration and status
+ */
+EAPI void
+ecore_x_netwm_desk_count_set(Ecore_X_Window root,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS,
+ &n_desks, 1);
+}
+
+EAPI void
+ecore_x_netwm_desk_roots_set(Ecore_X_Window root,
+ Ecore_X_Window *vroots,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(root,
+ ECORE_X_ATOM_NET_VIRTUAL_ROOTS,
+ vroots,
+ n_desks);
+}
+
+EAPI void
+ecore_x_netwm_desk_names_set(Ecore_X_Window root,
+ const char **names,
+ unsigned int n_desks)
+{
+ char ss[32], *buf, *t;
+ const char *s;
+ unsigned int i;
+ int l, len;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ buf = NULL;
+ len = 0;
+
+ for (i = 0; i < n_desks; i++)
+ {
+ s = (names) ? names[i] : NULL;
+ if (!s)
+ {
+ /* Default to "Desk-<number>" */
+ sprintf(ss, "Desk-%d", i);
+ s = ss;
+ }
+
+ l = strlen(s) + 1;
+ t = realloc(buf, len + l);
+ if (t)
+ {
+ buf = t;
+ memcpy(buf + len, s, l);
+ }
+ len += l;
+ }
+
+ _ATOM_SET_UTF8_STRING_LIST(root, ECORE_X_ATOM_NET_DESKTOP_NAMES, buf, len);
+
+ free(buf);
+}
+
+EAPI void
+ecore_x_netwm_desk_size_set(Ecore_X_Window root,
+ unsigned int width,
+ unsigned int height)
+{
+ unsigned int size[2];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ size[0] = width;
+ size[1] = height;
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_GEOMETRY, size,
+ 2);
+}
+
+EAPI void
+ecore_x_netwm_desk_viewports_set(Ecore_X_Window root,
+ unsigned int *origins,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_VIEWPORT,
+ origins, 2 * n_desks);
+}
+
+EAPI void
+ecore_x_netwm_desk_layout_set(Ecore_X_Window root,
+ int orientation,
+ int columns,
+ int rows,
+ int starting_corner)
+{
+ unsigned int layout[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ layout[0] = orientation;
+ layout[1] = columns;
+ layout[2] = rows;
+ layout[3] = starting_corner;
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_LAYOUT,
+ layout, 4);
+}
+
+EAPI void
+ecore_x_netwm_desk_workareas_set(Ecore_X_Window root,
+ unsigned int *areas,
+ unsigned int n_desks)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_WORKAREA, areas,
+ 4 * n_desks);
+}
+
+EAPI unsigned int *
+ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks)
+{
+ int ret;
+ unsigned int *areas = NULL;
+
+ if (!root) root = DefaultRootWindow(_ecore_x_disp);
+
+ ret = ecore_x_window_prop_card32_list_get(root, ECORE_X_ATOM_NET_WORKAREA,
+ &areas);
+ if (!areas)
+ {
+ if (n_desks) *n_desks = 0;
+ return 0;
+ }
+ if (n_desks) *n_desks = ret / 4;
+ return areas;
+}
+
+EAPI void
+ecore_x_netwm_desk_current_set(Ecore_X_Window root,
+ unsigned int desk)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_CURRENT_DESKTOP, &desk,
+ 1);
+}
+
+EAPI void
+ecore_x_netwm_showing_desktop_set(Ecore_X_Window root,
+ Eina_Bool on)
+{
+ unsigned int val;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ val = (on) ? 1 : 0;
+ ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_SHOWING_DESKTOP, &val,
+ 1);
+}
+
+/*
+ * Client status
+ */
+
+/* Mapping order */
+EAPI void
+ecore_x_netwm_client_list_set(Ecore_X_Window root,
+ Ecore_X_Window *p_clients,
+ unsigned int n_clients)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST,
+ p_clients, n_clients);
+}
+
+/* Stacking order */
+EAPI void
+ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root,
+ Ecore_X_Window *p_clients,
+ unsigned int n_clients)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST_STACKING,
+ p_clients, n_clients);
+}
+
+EAPI void
+ecore_x_netwm_client_active_set(Ecore_X_Window root,
+ Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_ACTIVE_WINDOW,
+ &win, 1);
+}
+
+EAPI void
+ecore_x_netwm_client_active_request(Ecore_X_Window root,
+ Ecore_X_Window win,
+ int type,
+ Ecore_X_Window current_win)
+{
+ XEvent xev;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_NET_ACTIVE_WINDOW;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = type;
+ xev.xclient.data.l[1] = CurrentTime;
+ xev.xclient.data.l[2] = current_win;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+EAPI void
+ecore_x_netwm_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_NAME, name);
+}
+
+EAPI int
+ecore_x_netwm_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (name)
+ *name = _ecore_x_window_prop_string_utf8_get(win,
+ ECORE_X_ATOM_NET_WM_NAME);
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_startup_id_set(Ecore_X_Window win,
+ const char *id)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_STARTUP_ID, id);
+}
+
+EAPI int
+ecore_x_netwm_startup_id_get(Ecore_X_Window win,
+ char **id)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (id)
+ *id = _ecore_x_window_prop_string_utf8_get(win,
+ ECORE_X_ATOM_NET_STARTUP_ID);
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_visible_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_NAME,
+ name);
+}
+
+EAPI int
+ecore_x_netwm_visible_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (name)
+ *name = _ecore_x_window_prop_string_utf8_get(
+ win,
+ ECORE_X_ATOM_NET_WM_VISIBLE_NAME);
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_icon_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_ICON_NAME,
+ name);
+}
+
+EAPI int
+ecore_x_netwm_icon_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (name)
+ *name = _ecore_x_window_prop_string_utf8_get(
+ win,
+ ECORE_X_ATOM_NET_WM_ICON_NAME);
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win,
+ const char *name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_prop_string_utf8_set(win,
+ ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME,
+ name);
+}
+
+EAPI int
+ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win,
+ char **name)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (name)
+ *name = _ecore_x_window_prop_string_utf8_get(
+ win,
+ ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME);
+
+ return 1;
+}
+
+EAPI void
+ecore_x_netwm_desktop_set(Ecore_X_Window win,
+ unsigned int desk)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_desktop_get(Ecore_X_Window win,
+ unsigned int *desk)
+{
+ int ret;
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_DESKTOP,
+ &tmp, 1);
+
+ if (desk)
+ *desk = tmp;
+
+ return ret == 1 ? EINA_TRUE : EINA_FALSE;
+}
+
+/*
+ * _NET_WM_STRUT is deprecated
+ */
+EAPI void
+ecore_x_netwm_strut_set(Ecore_X_Window win,
+ int left,
+ int right,
+ int top,
+ int bottom)
+{
+ unsigned int strut[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ strut[0] = left;
+ strut[1] = right;
+ strut[2] = top;
+ strut[3] = bottom;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4);
+}
+
+/*
+ * _NET_WM_STRUT is deprecated
+ */
+EAPI Eina_Bool
+ecore_x_netwm_strut_get(Ecore_X_Window win,
+ int *left,
+ int *right,
+ int *top,
+ int *bottom)
+{
+ int ret = 0;
+ unsigned int strut[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_NET_WM_STRUT,
+ strut,
+ 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (left)
+ *left = strut[0];
+
+ if (right)
+ *right = strut[1];
+
+ if (top)
+ *top = strut[2];
+
+ if (bottom)
+ *bottom = strut[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_strut_partial_set(Ecore_X_Window win,
+ int left,
+ int right,
+ int top,
+ int bottom,
+ int left_start_y,
+ int left_end_y,
+ int right_start_y,
+ int right_end_y,
+ int top_start_x,
+ int top_end_x,
+ int bottom_start_x,
+ int bottom_end_x)
+{
+ unsigned int strut[12];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ strut[0] = left;
+ strut[1] = right;
+ strut[2] = top;
+ strut[3] = bottom;
+ strut[4] = left_start_y;
+ strut[5] = left_end_y;
+ strut[6] = right_start_y;
+ strut[7] = right_end_y;
+ strut[8] = top_start_x;
+ strut[9] = top_end_x;
+ strut[10] = bottom_start_x;
+ strut[11] = bottom_end_x;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_NET_WM_STRUT_PARTIAL,
+ strut,
+ 12);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_strut_partial_get(Ecore_X_Window win,
+ int *left,
+ int *right,
+ int *top,
+ int *bottom,
+ int *left_start_y,
+ int *left_end_y,
+ int *right_start_y,
+ int *right_end_y,
+ int *top_start_x,
+ int *top_end_x,
+ int *bottom_start_x,
+ int *bottom_end_x)
+{
+ int ret = 0;
+ unsigned int strut[12];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_NET_WM_STRUT_PARTIAL,
+ strut,
+ 12);
+ if (ret != 12)
+ return EINA_FALSE;
+
+ if (left)
+ *left = strut[0];
+
+ if (right)
+ *right = strut[1];
+
+ if (top)
+ *top = strut[2];
+
+ if (bottom)
+ *bottom = strut[3];
+
+ if (left_start_y)
+ *left_start_y = strut[4];
+
+ if (left_end_y)
+ *left_end_y = strut[5];
+
+ if (right_start_y)
+ *right_start_y = strut[6];
+
+ if (right_end_y)
+ *right_end_y = strut[7];
+
+ if (top_start_x)
+ *top_start_x = strut[8];
+
+ if (top_end_x)
+ *top_end_x = strut[9];
+
+ if (bottom_start_x)
+ *bottom_start_x = strut[10];
+
+ if (bottom_end_x)
+ *bottom_end_x = strut[11];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_icons_set(Ecore_X_Window win,
+ Ecore_X_Icon *icon,
+ int num)
+{
+ unsigned int *data, *p, *p2;
+ unsigned int i, size, x, y;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ size = 0;
+ for (i = 0; i < (unsigned int)num; i++)
+ {
+ size += 2 + (icon[i].width * icon[i].height);
+ }
+ data = malloc(size * sizeof(unsigned int));
+ if (!data) return;
+ p = data;
+ for (i = 0; i < (unsigned int)num; i++)
+ {
+ p[0] = icon[i].width;
+ p[1] = icon[i].height;
+ p += 2;
+ p2 = icon[i].data;
+ for (y = 0; y < icon[i].height; y++)
+ {
+ for (x = 0; x < icon[i].width; x++)
+ {
+ unsigned int r, g, b, a;
+
+ a = (*p2 >> 24) & 0xff;
+ r = (*p2 >> 16) & 0xff;
+ g = (*p2 >> 8 ) & 0xff;
+ b = (*p2 ) & 0xff;
+ if ((a > 0) && (a < 255))
+ {
+ // unpremul
+ r = (r * 255) / a;
+ g = (g * 255) / a;
+ b = (b * 255) / a;
+ }
+ *p = (a << 24) | (r << 16) | (g << 8) | b;
+ p++;
+ p2++;
+ }
+ }
+ }
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON,
+ data, size);
+ free(data);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_icons_get(Ecore_X_Window win,
+ Ecore_X_Icon **icon,
+ int *num)
+{
+ unsigned int *data, *p;
+ unsigned int *src;
+ unsigned int len, icons, i;
+ int num_ret;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num)
+ *num = 0;
+
+ if (icon)
+ *icon = NULL;
+
+ num_ret = ecore_x_window_prop_card32_list_get(win, ECORE_X_ATOM_NET_WM_ICON,
+ &data);
+ if (num_ret <= 0)
+ return EINA_FALSE;
+
+ if (!data)
+ return EINA_FALSE;
+
+ if (num_ret < 2)
+ {
+ free(data);
+ return EINA_FALSE;
+ }
+
+ /* Check how many icons there are */
+ icons = 0;
+ p = data;
+ while (p)
+ {
+ len = p[0] * p[1];
+ p += (len + 2);
+ if ((p - data) > num_ret)
+ {
+ free(data);
+ return EINA_FALSE;
+ }
+
+ icons++;
+
+ if ((p - data) == num_ret)
+ p = NULL;
+ }
+ if (num)
+ *num = icons;
+
+ /* If the user doesn't want the icons, return */
+ if (!icon)
+ {
+ free(data);
+ return EINA_TRUE;
+ }
+
+ /* Allocate memory */
+ *icon = malloc(icons * sizeof(Ecore_X_Icon));
+ if (!(*icon))
+ {
+ free(data);
+ return EINA_FALSE;
+ }
+
+ /* Fetch the icons */
+ p = data;
+ for (i = 0; i < icons; i++)
+ {
+ unsigned int *ps, *pd, *pe;
+
+ len = p[0] * p[1];
+ ((*icon)[i]).width = p[0];
+ ((*icon)[i]).height = p[1];
+ src = &(p[2]);
+ ((*icon)[i]).data = malloc(len * sizeof(unsigned int));
+ if (!((*icon)[i]).data)
+ {
+ while (i)
+ free(((*icon)[--i]).data);
+ free(*icon);
+ free(data);
+ return EINA_FALSE;
+ }
+
+ pd = ((*icon)[i]).data;
+ ps = src;
+ pe = ps + len;
+ for (; ps < pe; ps++)
+ {
+ unsigned int r, g, b, a;
+
+ a = (*ps >> 24) & 0xff;
+ r = (((*ps >> 16) & 0xff) * a) / 255;
+ g = (((*ps >> 8) & 0xff) * a) / 255;
+ b = (((*ps) & 0xff) * a) / 255;
+ *pd = (a << 24) | (r << 16) | (g << 8) | (b);
+ pd++;
+ }
+ p += (len + 2);
+ }
+
+ free(data);
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_icon_geometry_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ unsigned int geometry[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ geometry[0] = x;
+ geometry[1] = y;
+ geometry[2] = width;
+ geometry[3] = height;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_NET_WM_ICON_GEOMETRY,
+ geometry,
+ 4);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_icon_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ int ret;
+ unsigned int geometry[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_NET_WM_ICON_GEOMETRY,
+ geometry,
+ 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (x)
+ *x = geometry[0];
+
+ if (y)
+ *y = geometry[1];
+
+ if (width)
+ *width = geometry[2];
+
+ if (height)
+ *height = geometry[3];
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_pid_set(Ecore_X_Window win,
+ int pid)
+{
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ tmp = pid;
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_PID,
+ &tmp, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_pid_get(Ecore_X_Window win,
+ int *pid)
+{
+ int ret;
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_PID,
+ &tmp, 1);
+ if (pid)
+ *pid = tmp;
+
+ return ret == 1 ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_netwm_handled_icons_set(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
+ NULL, 0);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_handled_icons_get(Ecore_X_Window win)
+{
+ int ret = 0;
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
+ NULL, 0);
+ return ret == 0 ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_netwm_user_time_set(Ecore_X_Window win,
+ unsigned int tim)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_USER_TIME,
+ &tim, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_user_time_get(Ecore_X_Window win,
+ unsigned int *tim)
+{
+ int ret;
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_USER_TIME,
+ &tmp, 1);
+ if (tim)
+ *tim = tmp;
+
+ return ret == 1 ? EINA_TRUE : EINA_FALSE;
+}
+
+Ecore_X_Window_State
+_ecore_x_netwm_state_get(Ecore_X_Atom a)
+{
+ if (a == ECORE_X_ATOM_NET_WM_STATE_MODAL)
+ return ECORE_X_WINDOW_STATE_MODAL;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_STICKY)
+ return ECORE_X_WINDOW_STATE_STICKY;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
+ return ECORE_X_WINDOW_STATE_MAXIMIZED_VERT;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
+ return ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_SHADED)
+ return ECORE_X_WINDOW_STATE_SHADED;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR)
+ return ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER)
+ return ECORE_X_WINDOW_STATE_SKIP_PAGER;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_HIDDEN)
+ return ECORE_X_WINDOW_STATE_HIDDEN;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN)
+ return ECORE_X_WINDOW_STATE_FULLSCREEN;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_ABOVE)
+ return ECORE_X_WINDOW_STATE_ABOVE;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_BELOW)
+ return ECORE_X_WINDOW_STATE_BELOW;
+ else if (a == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION)
+ return ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION;
+ else
+ return ECORE_X_WINDOW_STATE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_x_netwm_state_atom_get(Ecore_X_Window_State s)
+{
+ switch (s)
+ {
+ case ECORE_X_WINDOW_STATE_MODAL:
+ return ECORE_X_ATOM_NET_WM_STATE_MODAL;
+
+ case ECORE_X_WINDOW_STATE_STICKY:
+ return ECORE_X_ATOM_NET_WM_STATE_STICKY;
+
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
+ return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT;
+
+ case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
+ return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ;
+
+ case ECORE_X_WINDOW_STATE_SHADED:
+ return ECORE_X_ATOM_NET_WM_STATE_SHADED;
+
+ case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
+ return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR;
+
+ case ECORE_X_WINDOW_STATE_SKIP_PAGER:
+ return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER;
+
+ case ECORE_X_WINDOW_STATE_HIDDEN:
+ return ECORE_X_ATOM_NET_WM_STATE_HIDDEN;
+
+ case ECORE_X_WINDOW_STATE_FULLSCREEN:
+ return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN;
+
+ case ECORE_X_WINDOW_STATE_ABOVE:
+ return ECORE_X_ATOM_NET_WM_STATE_ABOVE;
+
+ case ECORE_X_WINDOW_STATE_BELOW:
+ return ECORE_X_ATOM_NET_WM_STATE_BELOW;
+
+ case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION:
+ return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION;
+
+ default:
+ return 0;
+ }
+}
+
+EAPI void
+ecore_x_netwm_window_state_set(Ecore_X_Window win,
+ Ecore_X_Window_State *state,
+ unsigned int num)
+{
+ Ecore_X_Atom *set;
+ unsigned int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!num)
+ {
+ ecore_x_window_prop_property_del(win, ECORE_X_ATOM_NET_WM_STATE);
+ return;
+ }
+
+ set = malloc(num * sizeof(Ecore_X_Atom));
+ if (!set)
+ return;
+
+ for (i = 0; i < num; i++)
+ set[i] = _ecore_x_netwm_state_atom_get(state[i]);
+
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_STATE, set, num);
+
+ free(set);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_window_state_get(Ecore_X_Window win,
+ Ecore_X_Window_State **state,
+ unsigned int *num)
+{
+ int num_ret, i;
+ Ecore_X_Atom *atoms;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num)
+ *num = 0;
+
+ if (state)
+ *state = NULL;
+
+ num_ret = ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_STATE,
+ &atoms);
+ if (num_ret <= 0)
+ return EINA_FALSE;
+
+ if (state)
+ {
+ *state = malloc(num_ret * sizeof(Ecore_X_Window_State));
+ if (*state)
+ for (i = 0; i < num_ret; ++i)
+ (*state)[i] = _ecore_x_netwm_state_get(atoms[i]);
+
+ if (num)
+ *num = num_ret;
+ }
+
+ free(atoms);
+ return EINA_TRUE;
+}
+
+static Ecore_X_Window_Type
+_ecore_x_netwm_window_type_type_get(Ecore_X_Atom atom)
+{
+ if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP)
+ return ECORE_X_WINDOW_TYPE_DESKTOP;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK)
+ return ECORE_X_WINDOW_TYPE_DOCK;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR)
+ return ECORE_X_WINDOW_TYPE_TOOLBAR;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU)
+ return ECORE_X_WINDOW_TYPE_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY)
+ return ECORE_X_WINDOW_TYPE_UTILITY;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH)
+ return ECORE_X_WINDOW_TYPE_SPLASH;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG)
+ return ECORE_X_WINDOW_TYPE_DIALOG;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL)
+ return ECORE_X_WINDOW_TYPE_NORMAL;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
+ return ECORE_X_WINDOW_TYPE_DROPDOWN_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU)
+ return ECORE_X_WINDOW_TYPE_POPUP_MENU;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP)
+ return ECORE_X_WINDOW_TYPE_TOOLTIP;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION)
+ return ECORE_X_WINDOW_TYPE_NOTIFICATION;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO)
+ return ECORE_X_WINDOW_TYPE_COMBO;
+ else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND)
+ return ECORE_X_WINDOW_TYPE_DND;
+ else
+ return ECORE_X_WINDOW_TYPE_UNKNOWN;
+}
+
+static Ecore_X_Atom
+_ecore_x_netwm_window_type_atom_get(Ecore_X_Window_Type type)
+{
+ switch (type)
+ {
+ case ECORE_X_WINDOW_TYPE_DESKTOP:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP;
+
+ case ECORE_X_WINDOW_TYPE_DOCK:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK;
+
+ case ECORE_X_WINDOW_TYPE_TOOLBAR:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;
+
+ case ECORE_X_WINDOW_TYPE_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU;
+
+ case ECORE_X_WINDOW_TYPE_UTILITY:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY;
+
+ case ECORE_X_WINDOW_TYPE_SPLASH:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH;
+
+ case ECORE_X_WINDOW_TYPE_DIALOG:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG;
+
+ case ECORE_X_WINDOW_TYPE_NORMAL:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL;
+
+ case ECORE_X_WINDOW_TYPE_DROPDOWN_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+
+ case ECORE_X_WINDOW_TYPE_POPUP_MENU:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU;
+
+ case ECORE_X_WINDOW_TYPE_TOOLTIP:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP;
+
+ case ECORE_X_WINDOW_TYPE_NOTIFICATION:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION;
+
+ case ECORE_X_WINDOW_TYPE_COMBO:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO;
+
+ case ECORE_X_WINDOW_TYPE_DND:
+ return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * FIXME: We should set WM_TRANSIENT_FOR if type is ECORE_X_WINDOW_TYPE_TOOLBAR
+ * , ECORE_X_WINDOW_TYPE_MENU or ECORE_X_WINDOW_TYPE_DIALOG
+ */
+EAPI void
+ecore_x_netwm_window_type_set(Ecore_X_Window win,
+ Ecore_X_Window_Type type)
+{
+ Ecore_X_Atom atom;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ atom = _ecore_x_netwm_window_type_atom_get(type);
+ ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atom, 1);
+}
+
+/* FIXME: Maybe return 0 on some conditions? */
+EAPI Eina_Bool
+ecore_x_netwm_window_type_get(Ecore_X_Window win,
+ Ecore_X_Window_Type *type)
+{
+ int num;
+ Ecore_X_Atom *atoms = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (type)
+ *type = ECORE_X_WINDOW_TYPE_NORMAL;
+
+ num = ecore_x_window_prop_atom_list_get(win,
+ ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atoms);
+ if ((type) && (num >= 1) && (atoms))
+ *type = _ecore_x_netwm_window_type_type_get(atoms[0]);
+
+ free(atoms);
+ if (num >= 1)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+EAPI int
+ecore_x_netwm_window_types_get(Ecore_X_Window win,
+ Ecore_X_Window_Type **types)
+{
+ int num, i;
+ Ecore_X_Atom *atoms = NULL;
+ Ecore_X_Window_Type *atoms2 = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (types)
+ *types = NULL;
+
+ num = ecore_x_window_prop_atom_list_get(win,
+ ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atoms);
+ if ((num <= 0) || (!atoms))
+ {
+ if (atoms)
+ free(atoms);
+
+ return 0;
+ }
+
+ atoms2 = malloc(num * sizeof(Ecore_X_Window_Type));
+ if (!atoms2)
+ return 0;
+
+ for (i = 0; i < num; i++)
+ atoms2[i] = _ecore_x_netwm_window_type_type_get(atoms[i]);
+ free(atoms);
+ if (types)
+ *types = atoms2;
+ else
+ free(atoms2);
+
+ return num;
+}
+
+static Ecore_X_Atom
+_ecore_x_netwm_action_atom_get(Ecore_X_Action action)
+{
+ switch (action)
+ {
+ case ECORE_X_ACTION_MOVE:
+ return ECORE_X_ATOM_NET_WM_ACTION_MOVE;
+
+ case ECORE_X_ACTION_RESIZE:
+ return ECORE_X_ATOM_NET_WM_ACTION_RESIZE;
+
+ case ECORE_X_ACTION_MINIMIZE:
+ return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;
+
+ case ECORE_X_ACTION_SHADE:
+ return ECORE_X_ATOM_NET_WM_ACTION_SHADE;
+
+ case ECORE_X_ACTION_STICK:
+ return ECORE_X_ATOM_NET_WM_ACTION_STICK;
+
+ case ECORE_X_ACTION_MAXIMIZE_HORZ:
+ return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;
+
+ case ECORE_X_ACTION_MAXIMIZE_VERT:
+ return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;
+
+ case ECORE_X_ACTION_FULLSCREEN:
+ return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;
+
+ case ECORE_X_ACTION_CHANGE_DESKTOP:
+ return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;
+
+ case ECORE_X_ACTION_CLOSE:
+ return ECORE_X_ATOM_NET_WM_ACTION_CLOSE;
+
+ case ECORE_X_ACTION_ABOVE:
+ return ECORE_X_ATOM_NET_WM_ACTION_ABOVE;
+
+ case ECORE_X_ACTION_BELOW:
+ return ECORE_X_ATOM_NET_WM_ACTION_BELOW;
+
+ default:
+ return 0;
+ }
+}
+
+/* FIXME: Get complete list */
+EAPI Eina_Bool
+ecore_x_netwm_allowed_action_isset(Ecore_X_Window win,
+ Ecore_X_Action action)
+{
+ int num, i;
+ Ecore_X_Atom *atoms, atom;
+ Eina_Bool ret = EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ num = ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
+ &atoms);
+ if (num <= 0)
+ return ret;
+
+ atom = _ecore_x_netwm_action_atom_get(action);
+
+ for (i = 0; i < num; ++i)
+ {
+ if (atom == atoms[i])
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+ free(atoms);
+ return ret;
+}
+
+/* FIXME: Set complete list */
+EAPI void
+ecore_x_netwm_allowed_action_set(Ecore_X_Window win,
+ Ecore_X_Action *action,
+ unsigned int num)
+{
+ Ecore_X_Atom *set;
+ unsigned int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!num)
+ {
+ ecore_x_window_prop_property_del(win,
+ ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS);
+ return;
+ }
+
+ set = malloc(num * sizeof(Ecore_X_Atom));
+ if (!set)
+ return;
+
+ for (i = 0; i < num; i++)
+ set[i] = _ecore_x_netwm_action_atom_get(action[i]);
+
+ ecore_x_window_prop_atom_set(win,
+ ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
+ set,
+ num);
+
+ free(set);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_allowed_action_get(Ecore_X_Window win,
+ Ecore_X_Action **action,
+ unsigned int *num)
+{
+ int num_ret, i;
+ Ecore_X_Atom *atoms;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num)
+ *num = 0;
+
+ if (action)
+ *action = NULL;
+
+ num_ret = ecore_x_window_prop_atom_list_get(
+ win,
+ ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
+ &atoms);
+ if (num_ret <= 0)
+ return EINA_FALSE;
+
+ if (action)
+ {
+ *action = malloc(num_ret * sizeof(Ecore_X_Action));
+ if (*action)
+ for (i = 0; i < num_ret; ++i)
+ (*action)[i] = _ecore_x_netwm_action_atom_get(atoms[i]);
+
+ if (num)
+ *num = num_ret;
+ }
+
+ free(atoms);
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_x_netwm_opacity_set(Ecore_X_Window win,
+ unsigned int opacity)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
+ &opacity, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_opacity_get(Ecore_X_Window win,
+ unsigned int *opacity)
+{
+ int ret;
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
+ &tmp, 1);
+ if (opacity)
+ *opacity = tmp;
+
+ return ret == 1 ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_netwm_frame_size_set(Ecore_X_Window win,
+ int fl,
+ int fr,
+ int ft,
+ int fb)
+{
+ unsigned int frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ frames[0] = fl;
+ frames[1] = fr;
+ frames[2] = ft;
+ frames[3] = fb;
+ ecore_x_window_prop_card32_set(win,
+ ECORE_X_ATOM_NET_FRAME_EXTENTS,
+ frames,
+ 4);
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_frame_size_get(Ecore_X_Window win,
+ int *fl,
+ int *fr,
+ int *ft,
+ int *fb)
+{
+ int ret = 0;
+ unsigned int frames[4];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(win,
+ ECORE_X_ATOM_NET_FRAME_EXTENTS,
+ frames,
+ 4);
+ if (ret != 4)
+ return EINA_FALSE;
+
+ if (fl)
+ *fl = frames[0];
+
+ if (fr)
+ *fr = frames[1];
+
+ if (ft)
+ *ft = frames[2];
+
+ if (fb)
+ *fb = frames[3];
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_netwm_sync_counter_get(Ecore_X_Window win,
+ Ecore_X_Sync_Counter *counter)
+{
+ int ret;
+ unsigned int tmp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ret = ecore_x_window_prop_card32_get(
+ win,
+ ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
+ &tmp,
+ 1);
+
+ if (counter)
+ *counter = tmp;
+
+ return ret == 1 ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_netwm_ping_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = ECORE_X_ATOM_NET_WM_PING;
+ xev.xclient.data.l[1] = _ecore_x_event_last_time;
+ xev.xclient.data.l[2] = win;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev);
+}
+
+EAPI void
+ecore_x_netwm_sync_request_send(Ecore_X_Window win,
+ unsigned int serial)
+{
+ XSyncValue value;
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntToValue(&value, (int)serial);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
+ xev.xclient.data.l[1] = _ecore_x_event_last_time;
+ xev.xclient.data.l[2] = XSyncValueLow32(value);
+ xev.xclient.data.l[3] = XSyncValueHigh32(value);
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev);
+}
+
+EAPI void
+ecore_x_netwm_state_request_send(Ecore_X_Window win,
+ Ecore_X_Window root,
+ Ecore_X_Window_State s1,
+ Ecore_X_Window_State s2,
+ Eina_Bool set)
+{
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.format = 32;
+ xev.xclient.message_type = ECORE_X_ATOM_NET_WM_STATE;
+ xev.xclient.data.l[0] = !!set;
+ xev.xclient.data.l[1] = _ecore_x_netwm_state_atom_get(s1);
+ xev.xclient.data.l[2] = _ecore_x_netwm_state_atom_get(s2);
+ /* 1 == normal client, if someone wants to use this
+ * function in a pager, this should be 2 */
+ xev.xclient.data.l[3] = 1;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+}
+
+EAPI void
+ecore_x_netwm_desktop_request_send(Ecore_X_Window win,
+ Ecore_X_Window root,
+ unsigned int desktop)
+{
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!root)
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.format = 32;
+ xev.xclient.message_type = ECORE_X_ATOM_NET_WM_DESKTOP;
+ xev.xclient.data.l[0] = desktop;
+
+ XSendEvent(_ecore_x_disp, root, False,
+ SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+}
+
+EAPI void
+ecore_x_netwm_moveresize_request_send(Ecore_X_Window win,
+ int x,
+ int y,
+ Ecore_X_Netwm_Direction direction,
+ unsigned int button)
+{
+ XEvent xev;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.window = win;
+ xev.xclient.type = ClientMessage;
+ xev.xclient.message_type = ECORE_X_ATOM_NET_WM_MOVERESIZE;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = x;
+ xev.xclient.data.l[1] = y;
+ xev.xclient.data.l[2] = direction;
+ xev.xclient.data.l[3] = button;
+ xev.xclient.data.l[4] = 1;
+
+ XSendEvent(_ecore_x_disp, win, False,
+ SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+}
+
+int
+_ecore_x_netwm_startup_info_begin(Ecore_X_Window win EINA_UNUSED,
+ char *data EINA_UNUSED)
+{
+#if 0
+ Ecore_X_Startup_Info *info;
+ unsigned char *exists = 0;
+
+ if (!startup_info)
+ return 0;
+
+ info = eina_hash_find(startup_info, (void *)win);
+ if (info)
+ {
+ exists = 1;
+ WRN("Already got info for win: 0x%x", win);
+ _ecore_x_netwm_startup_info_free(info);
+ }
+
+ info = calloc(1, sizeof(Ecore_X_Startup_Info));
+ if (!info)
+ return 0;
+
+ info->win = win;
+ info->length = 0;
+ info->buffer_size = 161;
+ info->buffer = calloc(info->buffer_size, sizeof(char));
+ if (!info->buffer)
+ {
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+
+ memcpy(info->buffer, data, 20);
+ info->length += 20;
+ info->buffer[info->length] = 0;
+ if (exists)
+ eina_hash_modify(startup_info, (void *)info->win, info);
+ else
+ eina_hash_add(startup_info, (void *)info->win, info);
+
+ if (strlen(info->buffer) != 20)
+ /* We have a '\0' in there, the message is done */
+ _ecore_x_netwm_startup_info_process(info);
+
+#endif /* if 0 */
+ return 1;
+}
+
+int
+_ecore_x_netwm_startup_info(Ecore_X_Window win EINA_UNUSED,
+ char *data EINA_UNUSED)
+{
+#if 0
+ Ecore_X_Startup_Info *info;
+ char *p;
+
+ if (!startup_info)
+ return 0;
+
+ info = eina_hash_find(startup_info, (void *)win);
+ if (!info)
+ return 0;
+
+ if ((info->length + 20) > info->buffer_size)
+ {
+ info->buffer_size += 160;
+ info->buffer = realloc(info->buffer, info->buffer_size * sizeof(char));
+ if (!info->buffer)
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+ }
+
+ memcpy(info->buffer + info->length, data, 20);
+ p = info->buffer + info->length;
+ info->length += 20;
+ info->buffer[info->length] = 0;
+ if (strlen(p) != 20)
+ /* We have a '\0' in there, the message is done */
+ _ecore_x_netwm_startup_info_process(info);
+
+#endif /* if 0 */
+ return 1;
+}
+
+/*
+ * Set UTF-8 string property
+ */
+static void
+_ecore_x_window_prop_string_utf8_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ const char *str)
+{
+ XChangeProperty(_ecore_x_disp, win, atom, ECORE_X_ATOM_UTF8_STRING, 8,
+ PropModeReplace, (unsigned char *)str, strlen(str));
+}
+
+/*
+ * Get UTF-8 string property
+ */
+static char *
+_ecore_x_window_prop_string_utf8_get(Ecore_X_Window win,
+ Ecore_X_Atom atom)
+{
+ char *str;
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+
+ str = NULL;
+ prop_ret = NULL;
+ XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ ECORE_X_ATOM_UTF8_STRING, &type_ret,
+ &format_ret, &num_ret, &bytes_after, &prop_ret);
+ if (prop_ret && num_ret > 0 && format_ret == 8)
+ {
+ str = malloc(num_ret + 1);
+ if (str)
+ {
+ memcpy(str, prop_ret, num_ret);
+ str[num_ret] = '\0';
+ }
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return str;
+}
+
+#if 0 /* Unused */
+/*
+ * Process startup info
+ */
+static int
+_ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info)
+{
+ Ecore_X_Event_Startup_Sequence *e;
+ int event;
+ char *p;
+
+ p = strchr(info->buffer, ':');
+ if (!p)
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+
+ *p = 0;
+ if (!strcmp(info->buffer, "new"))
+ {
+ if (info->init)
+ event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE;
+ else
+ event = ECORE_X_EVENT_STARTUP_SEQUENCE_NEW;
+
+ info->init = 1;
+ }
+ else if (!strcmp(info->buffer, "change"))
+ event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE;
+ else if (!strcmp(info->buffer, "remove"))
+ event = ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE;
+ else
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+
+ p++;
+
+ if (!_ecore_x_netwm_startup_info_parse(info, p))
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+
+ if (info->init)
+ {
+ e = calloc(1, sizeof(Ecore_X_Event_Startup_Sequence));
+ if (!e)
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ return 0;
+ }
+
+ e->win = info->win;
+ ecore_event_add(event, e, NULL, NULL);
+ }
+
+ if (event == ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE)
+ {
+ eina_hash_del(startup_info, (void *)info->win);
+ _ecore_x_netwm_startup_info_free(info);
+ }
+ else
+ {
+ /* Discard buffer */
+ info->length = 0;
+ info->buffer[0] = 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Parse startup info
+ */
+static int
+_ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info,
+ char *data)
+{
+ while (*data)
+ {
+ int in_quot_sing, in_quot_dbl, escaped;
+ char *p, *pp;
+ char *key;
+ char value[1024];
+
+ /* Skip space */
+ while (*data == ' ')
+ data++;
+ /* Get key */
+ key = data;
+ data = strchr(key, '=');
+ if (!data)
+ return 0;
+
+ *data = 0;
+ data++;
+
+ /* Get value */
+ p = data;
+ pp = value;
+ in_quot_dbl = 0;
+ in_quot_sing = 0;
+ escaped = 0;
+ while (*p)
+ {
+ if ((pp - value) >= 1024)
+ return 0;
+
+ if (escaped)
+ {
+ *pp = *p;
+ pp++;
+ escaped = 0;
+ }
+ else if (in_quot_sing)
+ {
+ if (*p == '\\')
+ escaped = 1;
+ else if (*p == '\'')
+ in_quot_sing = 0;
+ else
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+ else if (in_quot_dbl)
+ {
+ if (*p == '\\')
+ escaped = 1;
+ else if (*p == '\"')
+ in_quot_dbl = 0;
+ else
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+ else
+ {
+ if (*p == '\\')
+ escaped = 1;
+ else if (*p == '\'')
+ in_quot_sing = 1;
+ else if (*p == '\"')
+ in_quot_dbl = 1;
+ else if (*p == ' ')
+ break;
+ else
+ {
+ *pp = *p;
+ pp++;
+ }
+ }
+
+ p++;
+ }
+ if ((in_quot_dbl) || (in_quot_sing))
+ return 0;
+
+ data = p;
+ *pp = 0;
+
+ /* Parse info */
+ if (!strcmp(key, "ID"))
+ {
+ if ((info->id) && (strcmp(info->id, value)))
+ return 0;
+
+ info->id = strdup(value);
+ p = strstr(value, "_TIME");
+ if (p)
+ info->timestamp = atoi(p + 5);
+ }
+ else if (!strcmp(key, "NAME"))
+ {
+ if (info->name)
+ free(info->name);
+
+ info->name = strdup(value);
+ }
+ else if (!strcmp(key, "SCREEN"))
+ info->screen = atoi(value);
+ else if (!strcmp(key, "BIN"))
+ {
+ if (info->bin)
+ free(info->bin);
+
+ info->bin = strdup(value);
+ }
+ else if (!strcmp(key, "ICON"))
+ {
+ if (info->icon)
+ free(info->icon);
+
+ info->icon = strdup(value);
+ }
+ else if (!strcmp(key, "DESKTOP"))
+ info->desktop = atoi(value);
+ else if (!strcmp(key, "TIMESTAMP"))
+ {
+ if (!info->timestamp)
+ info->timestamp = atoi(value);
+ }
+ else if (!strcmp(key, "DESCRIPTION"))
+ {
+ if (info->description)
+ free(info->description);
+
+ info->description = strdup(value);
+ }
+ else if (!strcmp(key, "WMCLASS"))
+ {
+ if (info->wmclass)
+ free(info->wmclass);
+
+ info->wmclass = strdup(value);
+ }
+ else if (!strcmp(key, "SILENT"))
+ info->silent = atoi(value);
+ else
+ ERR("Ecore X Sequence, Unknown: %s=%s", key, value);
+ }
+ if (!info->id)
+ return 0;
+
+ return 1;
+}
+
+#endif /* if 0 */
+
+/*
+ * Free startup info struct
+ */
+static void
+_ecore_x_netwm_startup_info_free(void *data)
+{
+ Ecore_X_Startup_Info *info;
+
+ info = data;
+ if (!info)
+ return;
+
+ if (info->buffer)
+ free(info->buffer);
+
+ if (info->id)
+ free(info->id);
+
+ if (info->name)
+ free(info->name);
+
+ if (info->bin)
+ free(info->bin);
+
+ if (info->icon)
+ free(info->icon);
+
+ if (info->description)
+ free(info->description);
+
+ if (info->wmclass)
+ free(info->wmclass);
+
+ free(info);
+}
+
+/*
+ * Is screen composited?
+ */
+EAPI Eina_Bool
+ecore_x_screen_is_composited(int screen)
+{
+ Ecore_X_Window win;
+ static Ecore_X_Atom atom = None;
+ char buf[32];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ snprintf(buf, sizeof(buf), "_NET_WM_CM_S%i", screen);
+ if (atom == None)
+ atom = XInternAtom(_ecore_x_disp, buf, False);
+
+ if (atom == None)
+ return EINA_FALSE;
+
+ win = XGetSelectionOwner(_ecore_x_disp, atom);
+
+ return (win != None) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_screen_is_composited_set(int screen,
+ Ecore_X_Window win)
+{
+ static Ecore_X_Atom atom = None;
+ char buf[32];
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ snprintf(buf, sizeof(buf), "_NET_WM_CM_S%i", screen);
+ if (atom == None)
+ atom = XInternAtom(_ecore_x_disp, buf, False);
+
+ if (atom == None)
+ return;
+
+ XSetSelectionOwner(_ecore_x_disp, atom, win, _ecore_x_event_last_time);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_pixmap.c b/src/lib/ecore_x/xlib/ecore_x_pixmap.c
new file mode 100644
index 0000000000..7b13615675
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_pixmap.c
@@ -0,0 +1,121 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+/**
+ * @defgroup Ecore_X_Pixmap_Group X Pixmap Functions
+ *
+ * Functions that operate on pixmaps.
+ */
+
+/**
+ * Creates a new pixmap.
+ * @param win Window used to determine which screen of the display the
+ * pixmap should be created on. If 0, the default root window
+ * is used.
+ * @param w Width of the new pixmap.
+ * @param h Height of the new pixmap.
+ * @param dep Depth of the pixmap. If 0, the default depth of the default
+ * screen is used.
+ * @return New pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI Ecore_X_Pixmap
+ecore_x_pixmap_new(Ecore_X_Window win,
+ int w,
+ int h,
+ int dep)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ if (dep == 0)
+ dep = DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp));
+
+ return XCreatePixmap(_ecore_x_disp, win, w, h, dep);
+}
+
+/**
+ * Deletes the reference to the given pixmap.
+ *
+ * If no other clients have a reference to the given pixmap, the server
+ * will destroy it.
+ *
+ * @param pmap The given pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_free(Ecore_X_Pixmap pmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XFreePixmap(_ecore_x_disp, pmap);
+}
+
+/**
+ * Pastes a rectangular area of the given pixmap onto the given drawable.
+ * @param pmap The given pixmap.
+ * @param dest The given drawable.
+ * @param gc The graphics context which governs which operation will
+ * be used to paste the area onto the drawable.
+ * @param sx The X position of the area on the pixmap.
+ * @param sy The Y position of the area on the pixmap.
+ * @param w The width of the area.
+ * @param h The height of the area.
+ * @param dx The X position at which to paste the area on @p dest.
+ * @param dy The Y position at which to paste the area on @p dest.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_paste(Ecore_X_Pixmap pmap,
+ Ecore_X_Drawable dest,
+ Ecore_X_GC gc,
+ int sx,
+ int sy,
+ int w,
+ int h,
+ int dx,
+ int dy)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XCopyArea(_ecore_x_disp, pmap, dest, gc, sx, sy, w, h, dx, dy);
+}
+
+/**
+ * Retrieves the size of the given pixmap.
+ * @param pmap The given pixmap.
+ * @param x Pointer to an integer in which to store the X position.
+ * @param y Pointer to an integer in which to store the Y position.
+ * @param w Pointer to an integer in which to store the width.
+ * @param h Pointer to an integer in which to store the height.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI void
+ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (pmap)
+ ecore_x_drawable_geometry_get(pmap, x, y, w, h);
+}
+
+/**
+ * Retrieves the depth of the given pixmap.
+ * @param pmap The given pixmap.
+ * @return The depth of the pixmap.
+ * @ingroup Ecore_X_Pixmap_Group
+ */
+EAPI int
+ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_drawable_depth_get(pmap);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_private.h b/src/lib/ecore_x/xlib/ecore_x_private.h
new file mode 100644
index 0000000000..f962ffb4b2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_private.h
@@ -0,0 +1,379 @@
+#ifndef _ECORE_X_PRIVATE_H
+#define _ECORE_X_PRIVATE_H
+
+#include <sys/param.h>
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* ifndef MAXHOSTNAMELEN */
+
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Xresource.h>
+#include <X11/keysymdef.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/sync.h>
+#include <X11/extensions/dpms.h>
+#ifdef ECORE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif /* ifdef ECORE_XCURSOR */
+#ifdef ECORE_XPRINT
+#include <X11/extensions/Print.h>
+#endif /* ifdef ECORE_XPRINT */
+#ifdef ECORE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif /* ifdef ECORE_XINERAMA */
+#ifdef ECORE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif /* ifdef ECORE_XRANDR */
+#ifdef ECORE_XSS
+#include <X11/extensions/scrnsaver.h>
+#endif /* ifdef ECORE_XSS */
+#ifdef ECORE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif /* ifdef ECORE_XRENDER */
+#ifdef ECORE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif /* ifdef ECORE_XFIXES */
+#ifdef ECORE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif /* ifdef ECORE_XCOMPOSITE */
+#ifdef ECORE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif /* ifdef ECORE_XDAMAGE */
+#ifdef ECORE_XGESTURE
+#include <X11/extensions/gesture.h>
+#include <X11/extensions/gestureproto.h>
+#endif /* ifdef ECORE_XGESTURE */
+#ifdef ECORE_XDPMS
+#include <X11/extensions/dpms.h>
+#endif /* ifdef ECORE_XDPMS */
+#ifdef ECORE_XKB
+#include <X11/XKBlib.h>
+#endif /* ifdef ECORE_XKB */
+#ifdef ECORE_XI2
+#include <X11/extensions/XInput2.h>
+#endif /* ifdef ECORE_XI2 */
+
+#ifndef XK_MISCELLANY
+# define XK_MISCELLANY 1
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_X.h"
+#include "Ecore_Input.h"
+
+extern int _ecore_xlib_log_dom;
+#ifdef ECORE_XLIB_DEFAULT_LOG_COLOR
+# undef ECORE_XLIB_DEFAULT_LOG_COLOR
+#endif /* ifdef ECORE_XLIB_DEFAULT_LOG_COLOR */
+#define ECORE_XLIB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif /* ifdef ERR */
+#define ERR(...) EINA_LOG_DOM_ERR(_ecore_xlib_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif /* ifdef DBG */
+#define DBG(...) EINA_LOG_DOM_DBG(_ecore_xlib_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif /* ifdef INF */
+#define INF(...) EINA_LOG_DOM_INFO(_ecore_xlib_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif /* ifdef WRN */
+#define WRN(...) EINA_LOG_DOM_WARN(_ecore_xlib_log_dom, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif /* ifdef CRIT */
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_xlib_log_dom, __VA_ARGS__)
+
+typedef struct _Ecore_X_Selection_Intern Ecore_X_Selection_Intern;
+
+struct _Ecore_X_Selection_Intern
+{
+ Ecore_X_Window win;
+ Ecore_X_Atom selection;
+ unsigned char *data;
+ int length;
+ Time time;
+};
+
+typedef struct _Ecore_X_Selection_Converter Ecore_X_Selection_Converter;
+
+struct _Ecore_X_Selection_Converter
+{
+ Ecore_X_Atom target;
+ Eina_Bool (*convert)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *type, int *typeseize);
+ Ecore_X_Selection_Converter *next;
+};
+
+typedef struct _Ecore_X_Selection_Parser Ecore_X_Selection_Parser;
+
+struct _Ecore_X_Selection_Parser
+{
+ char *target;
+ void *(*parse)(const char *target, void *data, int size, int format);
+ Ecore_X_Selection_Parser *next;
+};
+
+typedef struct _Ecore_X_DND_Source
+{
+ int version;
+ Ecore_X_Window win, dest;
+
+ enum {
+ ECORE_X_DND_SOURCE_IDLE,
+ ECORE_X_DND_SOURCE_DRAGGING,
+ ECORE_X_DND_SOURCE_DROPPED,
+ ECORE_X_DND_SOURCE_CONVERTING
+ } state;
+
+ struct
+ {
+ short x, y;
+ unsigned short width, height;
+ } rectangle;
+
+ struct
+ {
+ Ecore_X_Window window;
+ int x, y;
+ } prev;
+
+ Time time;
+
+ Ecore_X_Atom action, accepted_action;
+
+ int will_accept;
+ int suppress;
+
+ int await_status;
+} Ecore_X_DND_Source;
+
+typedef struct _Ecore_X_DND_Target
+{
+ int version;
+ Ecore_X_Window win, source;
+
+ enum {
+ ECORE_X_DND_TARGET_IDLE,
+ ECORE_X_DND_TARGET_ENTERED
+ } state;
+
+ struct
+ {
+ int x, y;
+ } pos;
+
+ Time time;
+
+ Ecore_X_Atom action, accepted_action;
+
+ int will_accept;
+} Ecore_X_DND_Target;
+
+extern Display *_ecore_x_disp;
+extern double _ecore_x_double_click_time;
+extern Time _ecore_x_event_last_time;
+extern Window _ecore_x_event_last_win;
+extern int _ecore_x_event_last_root_x;
+extern int _ecore_x_event_last_root_y;
+extern Eina_Bool _ecore_x_xcursor;
+
+extern Ecore_X_Atom _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM];
+
+extern int _ecore_window_grabs_num;
+extern Window *_ecore_window_grabs;
+extern Eina_Bool (*_ecore_window_grab_replay_func)(void *data,
+ int event_type,
+ void *event);
+extern void *_ecore_window_grab_replay_data;
+
+extern Ecore_X_Window _ecore_x_private_win;
+
+void _ecore_x_error_handler_init(void);
+void _ecore_x_event_handle_any_event(XEvent *xevent);
+void _ecore_x_event_handle_key_press(XEvent *xevent);
+void _ecore_x_event_handle_key_release(XEvent *xevent);
+void _ecore_x_event_handle_button_press(XEvent *xevent);
+void _ecore_x_event_handle_button_release(XEvent *xevent);
+void _ecore_x_event_handle_motion_notify(XEvent *xevent);
+void _ecore_x_event_handle_enter_notify(XEvent *xevent);
+void _ecore_x_event_handle_leave_notify(XEvent *xevent);
+void _ecore_x_event_handle_focus_in(XEvent *xevent);
+void _ecore_x_event_handle_focus_out(XEvent *xevent);
+void _ecore_x_event_handle_keymap_notify(XEvent *xevent);
+void _ecore_x_event_handle_expose(XEvent *xevent);
+void _ecore_x_event_handle_graphics_expose(XEvent *xevent);
+void _ecore_x_event_handle_visibility_notify(XEvent *xevent);
+void _ecore_x_event_handle_create_notify(XEvent *xevent);
+void _ecore_x_event_handle_destroy_notify(XEvent *xevent);
+void _ecore_x_event_handle_unmap_notify(XEvent *xevent);
+void _ecore_x_event_handle_map_notify(XEvent *xevent);
+void _ecore_x_event_handle_map_request(XEvent *xevent);
+void _ecore_x_event_handle_reparent_notify(XEvent *xevent);
+void _ecore_x_event_handle_configure_notify(XEvent *xevent);
+void _ecore_x_event_handle_configure_request(XEvent *xevent);
+void _ecore_x_event_handle_gravity_notify(XEvent *xevent);
+void _ecore_x_event_handle_resize_request(XEvent *xevent);
+void _ecore_x_event_handle_circulate_notify(XEvent *xevent);
+void _ecore_x_event_handle_circulate_request(XEvent *xevent);
+void _ecore_x_event_handle_property_notify(XEvent *xevent);
+void _ecore_x_event_handle_selection_clear(XEvent *xevent);
+void _ecore_x_event_handle_selection_request(XEvent *xevent);
+void _ecore_x_event_handle_selection_notify(XEvent *xevent);
+void _ecore_x_event_handle_colormap_notify(XEvent *xevent);
+void _ecore_x_event_handle_client_message(XEvent *xevent);
+void _ecore_x_event_handle_mapping_notify(XEvent *xevent);
+void _ecore_x_event_handle_shape_change(XEvent *xevent);
+void _ecore_x_event_handle_screensaver_notify(XEvent *xevent);
+#ifdef ECORE_XGESTURE
+void _ecore_x_event_handle_gesture_notify_flick(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_pan(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_pinchrotation(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_tap(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_tapnhold(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_hold(XEvent *xevent);
+void _ecore_x_event_handle_gesture_notify_group(XEvent *xevent);
+#endif /* ifdef ECORE_XGESTURE */
+void _ecore_x_event_handle_sync_counter(XEvent *xevent);
+void _ecore_x_event_handle_sync_alarm(XEvent *xevent);
+#ifdef ECORE_XRANDR
+void _ecore_x_event_handle_randr_change(XEvent *xevent);
+void _ecore_x_event_handle_randr_notify(XEvent *xevent);
+#endif /* ifdef ECORE_XRANDR */
+#ifdef ECORE_XFIXES
+void _ecore_x_event_handle_fixes_selection_notify(XEvent *xevent);
+#endif /* ifdef ECORE_XFIXES */
+#ifdef ECORE_XDAMAGE
+void _ecore_x_event_handle_damage_notify(XEvent *xevent);
+#endif /* ifdef ECORE_XDAMAGE */
+#ifdef ECORE_XKB
+void _ecore_x_event_handle_xkb(XEvent *xevent);
+#endif /* ifdef ECORE_XKB */
+void _ecore_x_event_handle_generic_event(XEvent *xevent);
+
+void _ecore_x_selection_data_init(void);
+void _ecore_x_selection_shutdown(void);
+Ecore_X_Atom _ecore_x_selection_target_atom_get(const char *target);
+char *_ecore_x_selection_target_get(Ecore_X_Atom target);
+Ecore_X_Selection_Intern *_ecore_x_selection_get(Ecore_X_Atom selection);
+Eina_Bool _ecore_x_selection_set(Window w,
+ const void *data,
+ int len,
+ Ecore_X_Atom selection);
+int _ecore_x_selection_convert(Ecore_X_Atom selection,
+ Ecore_X_Atom target,
+ void **data_ret,
+ Ecore_X_Atom *targettype,
+ int *targetsize);
+void *_ecore_x_selection_parse(const char *target,
+ void *data,
+ int size,
+ int format);
+
+void _ecore_x_sync_magic_send(int val,
+ Ecore_X_Window swin);
+void _ecore_x_window_grab_remove(Ecore_X_Window win);
+void _ecore_x_key_grab_remove(Ecore_X_Window win);
+
+/* from dnd */
+void _ecore_x_dnd_init(void);
+Ecore_X_DND_Source *_ecore_x_dnd_source_get(void);
+Ecore_X_DND_Target *_ecore_x_dnd_target_get(void);
+void _ecore_x_dnd_drag(Ecore_X_Window root,
+ int x,
+ int y);
+void _ecore_x_dnd_shutdown(void);
+
+/* from netwm */
+Ecore_X_Window_State _ecore_x_netwm_state_get(Ecore_X_Atom a);
+int _ecore_x_netwm_startup_info_begin(Ecore_X_Window win,
+ char *data);
+int _ecore_x_netwm_startup_info(Ecore_X_Window win,
+ char *data);
+
+/* Fixes * Damage * Composite * DPMS */
+void _ecore_x_fixes_init(void);
+void _ecore_x_damage_init(void);
+void _ecore_x_composite_init(void);
+void _ecore_x_dpms_init(void);
+void _ecore_x_randr_init(void);
+void _ecore_x_gesture_init(void);
+
+void _ecore_x_atoms_init(void);
+
+extern int _ecore_x_xi2_opcode;
+
+void _ecore_x_events_init(void);
+void _ecore_x_events_shutdown(void);
+
+void _ecore_x_input_init(void);
+void _ecore_x_input_shutdown(void);
+void _ecore_x_input_handler(XEvent *xevent);
+/* from sync */
+
+void _ecore_mouse_move(unsigned int timestamp,
+ unsigned int xmodifiers,
+ int x,
+ int y,
+ int x_root,
+ int y_root,
+ unsigned int event_window,
+ unsigned int window,
+ unsigned int root_win,
+ int same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ double mx,
+ double my,
+ double mrx,
+ double mry);
+Ecore_Event_Mouse_Button *_ecore_mouse_button(int event,
+ unsigned int timestamp,
+ unsigned int xmodifiers,
+ unsigned int buttons,
+ int x,
+ int y,
+ int x_root,
+ int y_root,
+ unsigned int event_window,
+ unsigned int window,
+ unsigned int root_win,
+ int same_screen,
+ int dev,
+ double radx,
+ double rady,
+ double pressure,
+ double angle,
+ double mx,
+ double my,
+ double mrx,
+ double mry);
+
+void _ecore_x_modifiers_get(void);
+KeySym _ecore_x_XKeycodeToKeysym(Display *display, KeyCode keycode, int index);
+
+//#define LOGFNS 1
+
+#ifdef LOGFNS
+#include <stdio.h>
+#define LOGFN(fl, ln, fn) printf("-ECORE-X: %25s: %5i - %s\n", fl, ln, fn);
+#else /* ifdef LOGFNS */
+#define LOGFN(fl, ln, fn)
+#endif /* ifdef LOGFNS */
+
+#endif /* ifndef _ECORE_X_PRIVATE_H */
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr.c b/src/lib/ecore_x/xlib/ecore_x_randr.c
new file mode 100644
index 0000000000..58a28305ac
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr.c
@@ -0,0 +1,103 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+#include "ecore_x_randr.h"
+
+static Eina_Bool _randr_available = EINA_FALSE;
+#ifdef ECORE_XRANDR
+static int _randr_major, _randr_minor;
+int _randr_version;
+#define RANDR_1_1 ((1 << 16) | 1)
+#define RANDR_1_2 ((1 << 16) | 2)
+#define RANDR_1_3 ((1 << 16) | 3)
+
+#define RANDR_VALIDATE_ROOT(screen, \
+ root) ((screen = \
+ XRRRootToScreen(_ecore_x_disp, \
+ root)) != -1)
+
+#define Ecore_X_Randr_Unset -1
+
+XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * dpy,
+ Window window);
+
+#endif /* ifdef ECORE_XRANDR */
+
+void
+_ecore_x_randr_init(void)
+{
+#ifdef ECORE_XRANDR
+ _randr_major = 1;
+ _randr_minor = 3;
+ _randr_version = 0;
+
+ _ecore_x_randr_get_screen_resources = NULL;
+ if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor))
+ {
+ _randr_version = (_randr_major << 16) | _randr_minor;
+ if (_randr_version >= RANDR_1_3)
+ _ecore_x_randr_get_screen_resources = XRRGetScreenResourcesCurrent;
+ else if (_randr_version == RANDR_1_2)
+ _ecore_x_randr_get_screen_resources = XRRGetScreenResources;
+
+ _randr_available = EINA_TRUE;
+ }
+ else
+ _randr_available = EINA_FALSE;
+
+#else
+ _randr_available = EINA_FALSE;
+#endif
+}
+
+/*
+ * @brief Query whether randr is available or not.
+ *
+ * @return @c EINA_TRUE, if extension is available, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_query(void)
+{
+ return _randr_available;
+}
+
+/*
+ * @return version of the RandR extension supported by the server or, in case
+ * RandR extension is not available, Ecore_X_Randr_Unset (=-1).
+ * bit version information: 31 MAJOR 16 | 15 MINOR 0
+ */
+EAPI int
+ecore_x_randr_version_get(void)
+{
+#ifdef ECORE_XRANDR
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (_randr_available)
+ {
+ return _randr_version;
+ }
+ else
+ {
+ return Ecore_X_Randr_Unset;
+ }
+#else
+ return -1;
+#endif
+}
+
+Eina_Bool
+_ecore_x_randr_root_validate(Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Randr_Screen scr = -1;
+ if (root && RANDR_VALIDATE_ROOT(scr, root))
+ return EINA_TRUE;
+ else
+ return EINA_FALSE;
+
+#else
+ return EINA_FALSE;
+#endif
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr.h b/src/lib/ecore_x/xlib/ecore_x_randr.h
new file mode 100644
index 0000000000..eca3c0c32c
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr.h
@@ -0,0 +1,7 @@
+#ifndef ECORE_X_INLINE_X
+#define ECORE_X_INLINE_X
+Eina_Bool _ecore_x_randr_root_validate(Ecore_X_Window root);
+Eina_Bool _ecore_x_randr_output_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Output
+ output);
+#endif
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_11.c b/src/lib/ecore_x/xlib/ecore_x_randr_11.c
new file mode 100644
index 0000000000..7d2b3b34b5
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr_11.c
@@ -0,0 +1,334 @@
+/*
+ * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+#include "ecore_x_randr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define Ecore_X_Randr_None 0
+#ifdef ECORE_XRANDR
+
+#define RANDR_1_1 ((1 << 16) | 1)
+
+#define RANDR_VALIDATE_ROOT(screen, \
+ root) ((screen = \
+ XRRRootToScreen(_ecore_x_disp, \
+ root)) != -1)
+#define RANDR_CHECK_1_1_RET(ret) if (_randr_version < RANDR_1_1) \
+ return ret
+
+extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display *
+ dpy,
+ Window
+ window);
+extern int _randr_version;
+#endif /* ifdef ECORE_XRANDR */
+
+/*
+ * @param root window which's primary output will be queried
+ */
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ Rotation rot = Ecore_X_Randr_None, crot;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rot =
+ XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp,
+ root), &crot);
+ return rot;
+#else /* ifdef ECORE_XRANDR */
+ return Ecore_X_Randr_None;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @return the current orientation of the root window's screen primary output
+ */
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ Rotation crot = Ecore_X_Randr_None;
+ XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp,
+ root), &crot);
+ return crot;
+#else /* ifdef ECORE_XRANDR */
+ return Ecore_X_Randr_None;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @brief Sets a given screen's primary output's orientation.
+ *
+ * @param root Window which's screen's primary output will be queried.
+ * @param orientation orientation which should be set for the root window's
+ * screen primary output.
+ * @return @c EINA_TRUE if the primary output's orientation could be
+ * successfully altered.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_orientation_set(
+ Ecore_X_Window root,
+ Ecore_X_Randr_Orientation
+ orientation)
+{
+#ifdef ECORE_XRANDR
+ XRRScreenConfiguration *xrr_screen_cfg = NULL;
+ int sizeid;
+ Rotation crot;
+ Eina_Bool ret = EINA_FALSE;
+ if (!(xrr_screen_cfg = XRRGetScreenInfo(_ecore_x_disp, root)))
+ return EINA_FALSE;
+
+ sizeid = XRRConfigCurrentConfiguration(xrr_screen_cfg, &crot);
+ if (!XRRSetScreenConfig(_ecore_x_disp, xrr_screen_cfg, root, sizeid,
+ orientation, CurrentTime))
+ ret = EINA_TRUE;
+
+ if (xrr_screen_cfg)
+ XRRFreeScreenConfigInfo(xrr_screen_cfg);
+
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @brief gets a screen's primary output's possible sizes
+ * @param root window which's primary output will be queried
+ * @param num number of sizes reported as supported by the screen's primary output
+ * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL
+ */
+EAPI Ecore_X_Randr_Screen_Size_MM *
+ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Randr_Screen_Size_MM *ret = NULL;
+ XRRScreenSize *sizes;
+ int i, n;
+
+ /* we don't have to free sizes, because they're hold in a cache inside X*/
+ sizes =
+ XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp,
+ root), &n);
+ if ((!sizes) || (n <= 0)) return NULL;
+ ret = calloc(n, sizeof(Ecore_X_Randr_Screen_Size_MM));
+ if (!ret)
+ return NULL;
+
+ if (num)
+ *num = n;
+
+ for (i = 0; i < n; i++)
+ {
+ ret[i].width = sizes[i].width;
+ ret[i].height = sizes[i].height;
+ ret[i].width_mm = sizes[i].mwidth;
+ ret[i].height_mm = sizes[i].mheight;
+ }
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return NULL;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+EAPI void
+ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root,
+ int *w,
+ int *h,
+ int *w_mm,
+ int *h_mm,
+ int *size_index)
+{
+#ifdef ECORE_XRANDR
+ XRRScreenSize *sizes;
+ XRRScreenConfiguration *sc = NULL;
+ int idx;
+ Rotation orientation;
+ int n;
+
+ if (!(sc = XRRGetScreenInfo(_ecore_x_disp, root)))
+ {
+ ERR("Couldn't get screen information for %d", root);
+ return;
+ }
+
+ idx = XRRConfigCurrentConfiguration(sc, &orientation);
+
+ sizes =
+ XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp,
+ root), &n);
+ if ((idx < n) && (idx >= 0))
+ {
+ if (w)
+ *w = sizes[idx].width;
+
+ if (h)
+ *h = sizes[idx].height;
+
+ if (w_mm)
+ *w_mm = sizes[idx].mwidth;
+
+ if (h_mm)
+ *h_mm = sizes[idx].mheight;
+
+ if (size_index)
+ *size_index = idx;
+ }
+
+ XRRFreeScreenConfigInfo(sc);
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @brief Sets a given screen's primary output size, but disables all other
+ * outputs at the same time.
+ *
+ * @param root Window which's primary output will be queried.
+ * @param size_index Within the list of sizes reported as supported by the root
+ * window's screen primary output.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g.
+ * invalid times.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root,
+ int size_index)
+{
+#ifdef ECORE_XRANDR
+ XRRScreenConfiguration *sc = NULL;
+ Eina_Bool ret = EINA_FALSE;
+ int nsizes = 0;
+
+ if (size_index >= 0 && _ecore_x_randr_root_validate(root))
+ {
+ XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp,
+ root), &nsizes);
+
+ if (size_index < nsizes)
+ {
+ sc = XRRGetScreenInfo(_ecore_x_disp, root);
+ if (!XRRSetScreenConfig(_ecore_x_disp, sc,
+ root, size_index,
+ ECORE_X_RANDR_ORIENTATION_ROT_0, CurrentTime))
+ {
+ ret = EINA_TRUE;
+ }
+
+ if (sc)
+ XRRFreeScreenConfigInfo(sc);
+ }
+ }
+
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0
+ */
+EAPI Ecore_X_Randr_Refresh_Rate
+ecore_x_randr_screen_primary_output_current_refresh_rate_get(
+ Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Randr_Refresh_Rate ret = 0.0;
+ XRRScreenConfiguration *sc = NULL;
+
+ if (!_ecore_x_randr_root_validate(root) ||
+ !(sc = XRRGetScreenInfo(_ecore_x_disp, root)))
+ return ret;
+
+ ret = XRRConfigCurrentRate(sc);
+ if (sc)
+ XRRFreeScreenConfigInfo(sc);
+
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return 0.0;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+/*
+ * @param root window which's primary output will be queried
+ * @param size_index referencing the size to query valid refresh rates for
+ * @return currently used refresh rate or - if request failed or RandRR is not available - NULL
+ */
+EAPI Ecore_X_Randr_Refresh_Rate *
+ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root,
+ int size_index,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Randr_Refresh_Rate *ret = NULL, *rates = NULL;
+ Ecore_X_Randr_Screen scr;
+ int n;
+
+ if (num
+ && RANDR_VALIDATE_ROOT(scr, root)
+ && (rates = XRRRates(_ecore_x_disp, scr, size_index, &n)))
+ {
+ if (rates && (ret = malloc(sizeof(Ecore_X_Randr_Refresh_Rate) * n)))
+ {
+ memcpy(ret, rates, (sizeof(Ecore_X_Randr_Refresh_Rate) * n));
+ *num = n;
+ }
+ }
+
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return NULL;
+#endif /* ifdef ECORE_XRANDR */
+}
+
+//>= 1.1
+/*
+ * @brief Sets the current primary output's refresh rate.
+ *
+ * @param root Window which's primary output will be queried.
+ * @param size_index Referencing the size to be set.
+ * @param rate The refresh rate to be set.
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_primary_output_refresh_rate_set(
+ Ecore_X_Window root,
+ int size_index,
+ Ecore_X_Randr_Refresh_Rate
+ rate)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_1_RET(EINA_FALSE);
+ Eina_Bool ret = EINA_FALSE;
+ XRRScreenConfiguration *sc = NULL;
+
+ if (!(sc = XRRGetScreenInfo(_ecore_x_disp, root)))
+ return ret;
+
+ if (!XRRSetScreenConfigAndRate(_ecore_x_disp, sc,
+ root, size_index,
+ RR_Rotate_0, rate, CurrentTime))
+ ret = EINA_TRUE;
+
+ XRRFreeScreenConfigInfo(sc);
+ return ret;
+#else /* ifdef ECORE_XRANDR */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XRANDR */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_12.c b/src/lib/ecore_x/xlib/ecore_x_randr_12.c
new file mode 100644
index 0000000000..9e937d7bf7
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr_12.c
@@ -0,0 +1,2438 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include "ecore_x_private.h"
+#include "ecore_x_randr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define Ecore_X_Randr_None (Ecore_X_Randr_Crtc)0
+#define Ecore_X_Randr_Unset (Ecore_X_Randr_Crtc) - 1
+
+#ifdef ECORE_XRANDR
+
+#define RANDR_1_2 ((1 << 16) | 2)
+
+#define RANDR_VALIDATE_ROOT(screen, root) \
+ ((screen = XRRRootToScreen(_ecore_x_disp, root)) != -1)
+
+#define RANDR_CHECK_1_2_RET(ret) if (_randr_version < RANDR_1_2) \
+ return ret
+
+#define RANDR_PROPERTY_EDID "EDID"
+#define RANDR_PROPERTY_BACKLIGHT "Backlight"
+#define RANDR_PROPERTY_SIGNAL_FORMAT "SignalFormat"
+#define RANDR_PROPERTY_SIGNAL_PROPERTIES "SignalProperties"
+#define RANDR_PROPERTY_CONNECTOR_TYPE "ConnectorType"
+#define RANDR_PROPERTY_CONNECTOR_NUMBER "ConnectorNumber"
+#define RANDR_PROPERTY_COMPATIBILITY_LIST "CompatibilityList"
+#define RANDR_PROPERTY_CLONE_LIST "CloneList"
+
+extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display *
+ dpy,
+ Window
+ window);
+extern int _randr_version;
+#endif
+
+/**
+ * @brief Enable event selection. This enables basic interaction with
+ * output/crtc events and requires RandR >= 1.2.
+ *
+ * @param win Select this window's properties for RandR events.
+ * @param on Enable/disable selecting.
+ */
+EAPI void
+ecore_x_randr_events_select(Ecore_X_Window win,
+ Eina_Bool on)
+{
+#ifdef ECORE_XRANDR
+ int mask;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!on)
+ mask = 0;
+ else
+ {
+ mask = RRScreenChangeNotifyMask;
+ if (_randr_version >= RANDR_1_2)
+ mask |= (RRCrtcChangeNotifyMask |
+ RROutputChangeNotifyMask |
+ RROutputPropertyNotifyMask);
+ }
+
+ XRRSelectInput(_ecore_x_disp, win, mask);
+#endif
+}
+
+/**
+ * @brief Validates a CRTC for a given root window's screen.
+ *
+ * @param root The window which's default display will be queried.
+ * @param crtc The CRTC to be validated.
+ * @return In case it is found, @c EINA_TRUE will be returned, @c EINA_FALSE
+ * otherwise.
+ */
+static inline Eina_Bool
+_ecore_x_randr_crtc_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ XRRScreenResources *res = NULL;
+ int i;
+ Eina_Bool ret = EINA_FALSE;
+
+ if ((crtc == Ecore_X_Randr_None) ||
+ (crtc == Ecore_X_Randr_Unset))
+ return ret;
+
+ if (_ecore_x_randr_root_validate(root) && crtc &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->ncrtc; i++)
+ {
+ if (res->crtcs[i] == crtc)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+Eina_Bool
+_ecore_x_randr_output_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ Eina_Bool ret = EINA_FALSE;
+ XRRScreenResources *res = NULL;
+ int i;
+
+ if (_ecore_x_randr_root_validate(root) && output &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->noutput; i++)
+ {
+ if (res->outputs[i] == output)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+static inline Eina_Bool
+_ecore_x_randr_mode_validate(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ Eina_Bool ret = EINA_FALSE;
+ XRRScreenResources *res = NULL;
+ int i;
+
+ if (_ecore_x_randr_root_validate(root) && mode &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->nmode; i++)
+ {
+ if (res->modes[i].id == mode)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/*
+ * @param w width of screen in px
+ * @param h height of screen in px
+ */
+EAPI void
+ecore_x_randr_screen_current_size_get(Ecore_X_Window root,
+ int *w,
+ int *h,
+ int *w_mm,
+ int *h_mm)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ Ecore_X_Randr_Screen scr;
+
+ if (!RANDR_VALIDATE_ROOT(scr, root))
+ return;
+
+ if (w)
+ *w = DisplayWidth(_ecore_x_disp, scr);
+
+ if (h)
+ *h = DisplayHeight(_ecore_x_disp, scr);
+
+ if (w_mm)
+ *w_mm = DisplayWidthMM(_ecore_x_disp, scr);
+
+ if (h_mm)
+ *h_mm = DisplayHeightMM(_ecore_x_disp, scr);
+
+#endif
+}
+
+/*
+ * @param root window which's screen will be queried
+ * @param wmin minimum width the screen can be set to
+ * @param hmin minimum height the screen can be set to
+ * @param wmax maximum width the screen can be set to
+ * @param hmax maximum height the screen can be set to
+ */
+EAPI void
+ecore_x_randr_screen_size_range_get(Ecore_X_Window root,
+ int *wmin,
+ int *hmin,
+ int *wmax,
+ int *hmax)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ int twmin, thmin, twmax, thmax;
+ if (XRRGetScreenSizeRange (_ecore_x_disp, root, &twmin, &thmin, &twmax,
+ &thmax))
+ {
+ if (wmin)
+ *wmin = twmin;
+
+ if (hmin)
+ *hmin = thmin;
+
+ if (wmax)
+ *wmax = twmax;
+
+ if (hmax)
+ *hmax = thmax;
+ }
+
+#endif
+}
+
+/*
+ * @param root Window which's screen's size should be set. If invalid (e.g.
+ * @c NULL) no action is taken.
+ * @param w Width in px the screen should be set to. If out of valid
+ * boundaries, current value is assumed.
+ * @param h Height in px the screen should be set to. If out of valid
+ * boundaries, current value is assumed.
+ * @param w_mm Width in mm the screen should be set to. If @c 0, current
+ * aspect is assumed.
+ * @param h_mm Height in mm the screen should be set to. If @c 0, current
+ * aspect is assumed.
+ * @return @c EINA_TRUE if request was successfully sent or screen is already
+ * in requested size, @c EINA_FALSE if parameters are invalid.
+ */
+EAPI Eina_Bool
+ecore_x_randr_screen_current_size_set(Ecore_X_Window root,
+ int w,
+ int h,
+ int w_mm,
+ int h_mm)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ Ecore_X_Randr_Screen scr;
+ int w_c, h_c, w_mm_c, h_mm_c, twmin, thmin, twmax, thmax;
+
+ if (!RANDR_VALIDATE_ROOT(scr, root))
+ return EINA_FALSE;
+
+ ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, &w_mm_c, &h_mm_c);
+ if ((w == w_c) && (h == h_c) && (w_mm_c == w_mm) && (h_mm_c == h_mm))
+ return EINA_TRUE;
+
+ ecore_x_randr_screen_size_range_get(root, &twmin, &thmin, &twmax, &thmax);
+
+ if (((w != Ecore_X_Randr_None) &&
+ ((w < twmin) ||
+ (w > twmax))) ||
+ ((h != Ecore_X_Randr_None) && ((h < thmin) || (h > thmax))))
+ return EINA_FALSE;
+
+ if (w <= 0)
+ w = DisplayWidth(_ecore_x_disp, scr);
+
+ if (h <= 0)
+ h = DisplayHeight(_ecore_x_disp, scr);
+
+ if (w_mm <= 0)
+ w_mm =
+ (int)(((double)(DisplayWidthMM(_ecore_x_disp,
+ scr) /
+ (double)DisplayWidth(_ecore_x_disp,
+ scr))) * (double)w);
+
+ if (h_mm <= 0)
+ h_mm =
+ (int)(((double)(DisplayHeightMM(_ecore_x_disp,
+ scr) /
+ (double)DisplayHeight(_ecore_x_disp,
+ scr))) * (double)h);
+
+ XRRSetScreenSize (_ecore_x_disp, root, w, h, w_mm, h_mm);
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/*
+ * @brief get detailed information for all modes related to a root window's screen
+ * @param root window which's screen's ressources are queried
+ * @param num number of modes returned
+ * @return modes' information
+ */
+EAPI Ecore_X_Randr_Mode_Info **
+ecore_x_randr_modes_info_get(Ecore_X_Window root,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Mode_Info **ret = NULL;
+ int i;
+
+ if (_ecore_x_randr_root_validate(root) &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ if ((ret =
+ (Ecore_X_Randr_Mode_Info **)malloc(sizeof(
+ Ecore_X_Randr_Mode_Info *)
+ *
+ res->nmode)))
+ {
+ for (i = 0; i < res->nmode; i++)
+ {
+ if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ ret[i]->xid = res->modes[i].id;
+ ret[i]->width = res->modes[i].width;
+ ret[i]->height = res->modes[i].height;
+ ret[i]->dotClock = res->modes[i].dotClock;
+ ret[i]->hSyncStart = res->modes[i].hSyncStart;
+ ret[i]->hSyncEnd = res->modes[i].hSyncEnd;
+ ret[i]->hTotal = res->modes[i].hTotal;
+ ret[i]->hSkew = res->modes[i].hSkew;
+ ret[i]->vSyncStart = res->modes[i].vSyncStart;
+ ret[i]->vSyncEnd = res->modes[i].vSyncEnd;
+ ret[i]->vTotal = res->modes[i].vTotal;
+ if ((ret[i]->name = (malloc(res->modes[i].nameLength + 1))))
+ strncpy(ret[i]->name, res->modes[i].name,
+ (res->modes[i].nameLength + 1));
+ else
+ ret[i]->name = NULL;
+
+ ret[i]->nameLength = res->modes[i].nameLength;
+ ret[i]->modeFlags = res->modes[i].modeFlags;
+ }
+ else
+ {
+ while (i > 0)
+ free(ret[--i]);
+ free(ret);
+ ret = NULL;
+ break;
+ }
+ }
+ }
+
+ if (ret && num)
+ *num = res->nmode;
+
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief Add a mode to a display.
+ *
+ * @param root Window to which's screen's ressources are added.
+ * @param mode_info
+ * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode
+ * adding failed.
+ * @since 1.2.0
+ */
+EAPI Ecore_X_Randr_Mode
+ecore_x_randr_mode_info_add(Ecore_X_Window root,
+ Ecore_X_Randr_Mode_Info *mode_info)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ Ecore_X_Randr_Mode mode = Ecore_X_Randr_None;
+
+ if (_ecore_x_randr_root_validate(root) && mode_info)
+ mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo*)mode_info);
+
+ return mode;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+/*
+ * @brief Delete a mode from the display.
+ *
+ * @param mode_info
+ * @since 1.2.0
+ */
+EAPI void
+ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+
+ XRRDestroyMode(_ecore_x_disp, mode);
+#else
+ return;
+#endif
+}
+
+/*
+ * @brief get detailed information for a given mode id
+ * @param root window which's screen's ressources are queried
+ * @param mode the XID which identifies the mode of interest
+ * @return mode's detailed information
+ */
+EAPI Ecore_X_Randr_Mode_Info *
+ecore_x_randr_mode_info_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Mode_Info *ret = NULL;
+ int i;
+
+ if (_ecore_x_randr_root_validate(root) &&
+ (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->nmode; i++)
+ {
+ if ((res->modes[i].id == mode) &&
+ (ret = malloc(sizeof(Ecore_X_Randr_Mode_Info))))
+ {
+ ret->xid = res->modes[i].id;
+ ret->width = res->modes[i].width;
+ ret->height = res->modes[i].height;
+ ret->dotClock = res->modes[i].dotClock;
+ ret->hSyncStart = res->modes[i].hSyncStart;
+ ret->hSyncEnd = res->modes[i].hSyncEnd;
+ ret->hTotal = res->modes[i].hTotal;
+ ret->hSkew = res->modes[i].hSkew;
+ ret->vSyncStart = res->modes[i].vSyncStart;
+ ret->vSyncEnd = res->modes[i].vSyncEnd;
+ ret->vTotal = res->modes[i].vTotal;
+ ret->name = NULL;
+ ret->nameLength = 0;
+ if (res->modes[i].nameLength > 0)
+ {
+ ret->nameLength = res->modes[i].nameLength;
+ ret->name = malloc(res->modes[i].nameLength + 1);
+ if (ret->name)
+ memcpy(ret->name, res->modes[i].name,
+ res->modes[i].nameLength + 1);
+ }
+ ret->modeFlags = res->modes[i].modeFlags;
+ break;
+ }
+ }
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief Free detailed mode information. The pointer handed in will be set to
+ * @c NULL after freeing the memory.
+ *
+ * @param mode_info The mode information that should be freed.
+ */
+EAPI void
+ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ if (!mode_info)
+ return;
+
+ if (mode_info->name)
+ free(mode_info->name);
+
+ free(mode_info);
+ mode_info = NULL;
+#endif
+}
+
+/*
+ * @brief Get all known CRTCs related to a root window's screen.
+ *
+ * @param root Window which's screen's ressources are queried.
+ * @param num Number of CRTCs returned.
+ * @return CRTC IDs.
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_crtcs_get(Ecore_X_Window root,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Crtc *ret = NULL;
+
+ if (root &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc) * res->ncrtc)))
+ {
+ int i = 0;
+
+ if (num) *num = res->ncrtc;
+
+ for (i = 0; i < res->ncrtc; i++)
+ ret[i] = res->crtcs[i];
+ }
+
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead.
+ * @brief get the CRTCs, which display a certain window
+ * @param window window the displaying crtcs shall be found for
+ * @param num the number of crtcs displaying the window
+ * @return Array of crtcs that display a certain window. @c NULL if no crtcs
+ * was found that displays the specified window.
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_current_crtc_get(Ecore_X_Window window,
+ int *num)
+{
+ return ecore_x_randr_window_crtcs_get(window, num);
+}
+
+/*
+ * @brief get the CRTCs, which display a certain window
+ * @param window window the displaying crtcs shall be found for
+ * @param num the number of crtcs displaying the window
+ * @return Array of crtcs that display a certain window. @c NULL if no crtcs
+ * was found that displays the specified window.
+ * @since 1.2.0
+ */
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_window_crtcs_get(Ecore_X_Window window,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Window root;
+ Eina_Rectangle w_geo, c_geo;
+ Ecore_X_Randr_Crtc *crtcs;
+ Ecore_X_Randr_Mode mode;
+ Ecore_X_Randr_Output *ret = NULL;
+ Window tw;
+ int ncrtcs, i, nret = 0, rx = 0, ry = 0;
+
+ if (_randr_version < RANDR_1_2) goto _ecore_x_randr_window_crtcs_get_fail;
+
+ ecore_x_window_geometry_get(window,
+ &w_geo.x, &w_geo.y,
+ &w_geo.w, &w_geo.h);
+
+ root = ecore_x_window_root_get(window);
+ crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs);
+ if (!crtcs) goto _ecore_x_randr_window_crtcs_get_fail;
+
+ /* now get window RELATIVE to root window - thats what matters. */
+ XTranslateCoordinates(_ecore_x_disp, window, root, 0, 0, &rx, &ry, &tw);
+ w_geo.x = rx;
+ w_geo.y = ry;
+
+ ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc));
+ if (!ret)
+ {
+ free(crtcs);
+ goto _ecore_x_randr_window_crtcs_get_fail;
+ }
+ for (i = 0, nret = 0; i < ncrtcs; i++)
+ {
+ /* if crtc is not enabled, don't bother about it any further */
+ mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]);
+ if (mode == Ecore_X_Randr_None) continue;
+
+ ecore_x_randr_crtc_geometry_get(root, crtcs[i],
+ &c_geo.x, &c_geo.y,
+ &c_geo.w, &c_geo.h);
+ if (eina_rectangles_intersect(&w_geo, &c_geo))
+ {
+ ret[nret] = crtcs[i];
+ nret++;
+ }
+ }
+ free(crtcs);
+
+ if (num) *num = nret;
+ return ret;
+
+_ecore_x_randr_window_crtcs_get_fail:
+#endif
+ if (num) *num = 0;
+ return NULL;
+}
+
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_outputs_get(Ecore_X_Window root,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Output *ret = NULL;
+
+ if (root &&
+ (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * res->noutput)))
+ {
+ int i = 0;
+
+ if (num) *num = res->noutput;
+
+ for (i = 0; i < res->noutput; i++)
+ ret[i] = res->outputs[i];
+ }
+
+ if (res)
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+//Per Crtc
+/*
+ * @brief get a CRTC's outputs.
+ * @param root the root window which's screen will be queried
+ * @param num number of outputs referenced by given CRTC
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_crtc_outputs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Output *ret = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+
+ if (_ecore_x_randr_crtc_validate(root, crtc) &&
+ (res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)) &&
+ (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->noutput)))
+ {
+ int i = 0;
+
+ if (num) *num = crtc_info->noutput;
+
+ for (i = 0; i < crtc_info->noutput; i++)
+ ret[i] = crtc_info->outputs[i];
+ }
+
+ if (crtc_info)
+ XRRFreeCrtcInfo(crtc_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * @brief get a CRTC's possible outputs.
+ * @param root the root window which's screen will be queried
+ * @param num number of possible outputs referenced by given CRTC
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Output *ret = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+
+ if (_ecore_x_randr_crtc_validate(root, crtc) &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ if ((ret =
+ malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->npossible)))
+ {
+ int i = 0;
+
+ if (num) *num = crtc_info->npossible;
+
+ for (i = 0; i < crtc_info->npossible; i++)
+ ret[i] = crtc_info->possible[i];
+ }
+
+ XRRFreeCrtcInfo(crtc_info);
+ }
+
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+EAPI void
+ecore_x_randr_crtc_geometry_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+
+ if (_ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp,
+ root)) &&
+ (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ if (x)
+ *x = crtc_info->x;
+
+ if (y)
+ *y = crtc_info->y;
+
+ if (w)
+ *w = crtc_info->width;
+
+ if (h)
+ *h = crtc_info->height;
+
+ XRRFreeCrtcInfo(crtc_info);
+ XRRFreeScreenResources(res);
+ }
+
+#endif
+}
+
+/*
+ * @brief Sets the position of given CRTC within root window's screen.
+ *
+ * @param root The window's screen to be queried.
+ * @param crtc The CRTC which's position within the mentioned screen is to be
+ * altered.
+ * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current
+ * value will be kept.
+ * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current
+ * value will be kept.
+ * @return @c EINA_TRUE if position could successfully be altered.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_pos_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int x,
+ int y)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ int w_c, h_c, w_new = 0, h_new = 0;
+ Eina_Rectangle crtc_geo;
+
+ ecore_x_randr_crtc_geometry_get(root,
+ crtc,
+ &crtc_geo.x,
+ &crtc_geo.y,
+ &crtc_geo.w,
+ &crtc_geo.h);
+ ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, NULL, NULL);
+ if (x < 0)
+ x = crtc_geo.x;
+
+ if (y < 0)
+ y = crtc_geo.y;
+
+ if ((x + crtc_geo.w) > w_c)
+ w_new = x + crtc_geo.w;
+
+ if ((y + crtc_geo.h) > h_c)
+ h_new = y + crtc_geo.h;
+
+ if ((w_new != 0) || (h_new != 0))
+ if (!ecore_x_randr_screen_current_size_set(root, w_new, h_new, 0, 0))
+ return EINA_FALSE;
+
+ return ecore_x_randr_crtc_settings_set(root,
+ crtc,
+ NULL,
+ Ecore_X_Randr_Unset,
+ x,
+ y,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset);
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/**
+ * @brief Get the current set mode of a given CRTC
+ * @param root the window's screen to be queried
+ * @param crtc the CRTC which's should be queried
+ * @return currently set mode or - in case parameters are invalid -
+ * Ecore_X_Randr_Unset
+ */
+EAPI Ecore_X_Randr_Mode
+ecore_x_randr_crtc_mode_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_Unset);
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+ Ecore_X_Randr_Mode ret = Ecore_X_Randr_Unset;
+ if (_ecore_x_randr_root_validate(root) &&
+ _ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res =
+ _ecore_x_randr_get_screen_resources(_ecore_x_disp,
+ root)) &&
+ (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ ret = crtc_info->mode;
+ XRRFreeCrtcInfo(crtc_info);
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return Ecore_X_Randr_Unset;
+#endif
+}
+
+/**
+ * @brief Sets a mode for a CRTC and the outputs attached to it.
+ *
+ * @param root The window's screen to be queried.
+ * @param crtc The CRTC which shall be set.
+ * @param outputs Array of outputs which have to be compatible with the mode.
+ * If @c NULL, CRTC will be disabled.
+ * @param noutputs Number of outputs in array to be used. Use
+ * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs.
+ * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be
+ * disabled. If set to @c -1 the call will fail.
+ * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE
+ * otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_mode_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Output *outputs,
+ int noutputs,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if (mode == Ecore_X_Randr_Unset)
+ return EINA_FALSE;
+
+ return ecore_x_randr_crtc_settings_set(root,
+ crtc,
+ outputs,
+ noutputs,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset,
+ mode,
+ Ecore_X_Randr_Unset);
+#else
+ return EINA_FALSE;
+#endif
+}
+
+EAPI void
+ecore_x_randr_crtc_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *w,
+ int *h)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h);
+#endif
+}
+
+EAPI Ecore_X_Randr_Refresh_Rate
+ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(0.0);
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+ Ecore_X_Randr_Refresh_Rate ret = 0.0;
+ int i;
+
+ if (_ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->nmode; i++)
+ if (res->modes[i].id == mode)
+ {
+ if (res->modes[i].hTotal && res->modes[i].vTotal)
+ ret = ((double)res->modes[i].dotClock /
+ ((double)res->modes[i].hTotal *
+ (double)res->modes[i].vTotal));
+
+ break;
+ }
+ }
+
+ if (crtc_info)
+ XRRFreeCrtcInfo(crtc_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return ret;
+#else
+ return 0.0;
+#endif
+}
+
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_crtc_orientations_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+ XRRCrtcInfo *crtc_info = NULL;
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
+
+ if (_ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp,
+ root)) &&
+ (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ ret = crtc_info->rotations;
+ }
+ if (crtc_info)
+ XRRFreeCrtcInfo(crtc_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return ret;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+EAPI Ecore_X_Randr_Orientation
+ecore_x_randr_crtc_orientation_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+ XRRCrtcInfo *crtc_info = NULL;
+ XRRScreenResources *res = NULL;
+ Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None;
+
+ if (_ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp,
+ root)) &&
+ (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ ret = crtc_info->rotation;
+ }
+ if (crtc_info)
+ XRRFreeCrtcInfo(crtc_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return ret;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_randr_crtc_orientation_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Orientation orientation)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ Eina_Bool ret = EINA_FALSE;
+
+ if (orientation != Ecore_X_Randr_None)
+ {
+ ret = ecore_x_randr_crtc_settings_set(root,
+ crtc,
+ NULL,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset,
+ orientation);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+EAPI void
+ecore_x_randr_crtc_pos_get(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ int *x,
+ int *y)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+
+ ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL);
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_randr_crtc_clone_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc original,
+ Ecore_X_Randr_Crtc clon)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo *clone_crtc_info = NULL;
+ Ecore_X_Randr_Mode original_mode = Ecore_X_Randr_None;
+ Ecore_X_Randr_Orientation original_orientation = Ecore_X_Randr_None;
+ Eina_Bool ret = EINA_FALSE;
+ int x, y;
+
+ if (_ecore_x_randr_root_validate(root) &&
+ _ecore_x_randr_crtc_validate(root,
+ original) &&
+ _ecore_x_randr_crtc_validate(root,
+ clon) &&
+ (res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp,
+ root)) &&
+ (clone_crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, clon)))
+ {
+ ecore_x_randr_crtc_geometry_get(root, original, &x, &y, NULL, NULL);
+ original_mode = ecore_x_randr_crtc_mode_get(root, original);
+ original_orientation = ecore_x_randr_crtc_orientation_get(root,
+ original);
+ ret = ecore_x_randr_crtc_settings_set(root,
+ clon,
+ NULL,
+ Ecore_X_Randr_Unset,
+ x,
+ y,
+ original_mode,
+ original_orientation);
+ XRRFreeCrtcInfo(clone_crtc_info);
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/**
+ * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is
+ * auto enabled in it's preferred mode, when it was disabled before.
+ *
+ * @param root The root window which's default display will be queried.
+ * @param crtc The CRTC which's configuration should be altered.
+ * @param outputs An array of outputs, that should display this CRTC's content.
+ * @param noutputs Number of outputs in the array of outputs. If set to
+ * Ecore_X_Randr_Unset, current outputs and number of outputs will be used.
+ * If set to Ecore_X_Randr_None, CRTC will be disabled.
+ * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x
+ * corrdinate will be assumed.
+ * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y
+ * corrdinate will be assumed.
+ * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the
+ * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is
+ * assumed.
+ * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is
+ * used, the current mode is assumed.
+ * @return @c EINA_TRUE if the configuration alteration was successful,
+ * @c EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_settings_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc,
+ Ecore_X_Randr_Output *outputs,
+ int noutputs,
+ int x,
+ int y,
+ Ecore_X_Randr_Mode mode,
+ Ecore_X_Randr_Orientation orientation)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo *crtc_info = NULL;
+ Eina_Bool ret = EINA_FALSE;
+
+ if (_ecore_x_randr_crtc_validate(root,
+ crtc) &&
+ (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc)))
+ {
+ if ((mode == Ecore_X_Randr_None) ||
+ (noutputs == Ecore_X_Randr_None))
+ {
+ outputs = NULL;
+ noutputs = 0;
+ }
+ else if (noutputs == (int)Ecore_X_Randr_Unset)
+ {
+ outputs = (Ecore_X_Randr_Output *)crtc_info->outputs;
+ noutputs = crtc_info->noutput;
+ }
+
+ if (mode == Ecore_X_Randr_Unset)
+ mode = crtc_info->mode;
+
+ if (x < 0)
+ x = crtc_info->x;
+
+ if (y < 0)
+ y = crtc_info->y;
+
+ if (orientation == Ecore_X_Randr_Unset)
+ orientation = crtc_info->rotation;
+
+ if (!XRRSetCrtcConfig(_ecore_x_disp, res, crtc, CurrentTime,
+ x, y, mode, orientation, (RROutput *)outputs,
+ noutputs))
+ ret = EINA_TRUE;
+
+ XRRFreeCrtcInfo(crtc_info);
+ }
+
+ XRRFreeScreenResources(res);
+ }
+
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/**
+ * @brief Sets a CRTC relative to another one.
+ *
+ * @param root The root window which's default display will be set.
+ * @param crtc_r1 The CRTC to be positioned.
+ * @param crtc_r2 The CRTC the position should be relative to.
+ * @param policy The relation between the crtcs.
+ * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at
+ * CRTC2's borders.
+ * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE
+ * if repositioning failed or if position of new crtc would be out of given
+ * screen's min/max bounds.
+ */
+EAPI Eina_Bool
+ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root,
+ Ecore_X_Randr_Crtc crtc_r1,
+ Ecore_X_Randr_Crtc crtc_r2,
+ Ecore_X_Randr_Output_Policy policy,
+ Ecore_X_Randr_Relative_Alignment alignment)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ Eina_Rectangle r1_geo, r2_geo;
+ int w_max, h_max, cw, ch, x_n = Ecore_X_Randr_Unset, y_n =
+ Ecore_X_Randr_Unset;
+ /*
+ int r1_noutputs, r2_noutputs, r1_nmodes, i, j, outputs_mode_found, mode_w, mode_h;
+ Ecore_X_Randr_Output *r1_outputs, *r2_outputs, *r2_r1_outputs;
+ Ecore_X_Randr_Mode *r1_modes, r2_mode, r1_mode;
+ Eina_Bool ret;
+ */
+
+ if ((ecore_x_randr_crtc_mode_get(root, crtc_r1) == Ecore_X_Randr_None)
+ || (ecore_x_randr_crtc_mode_get(root, crtc_r2) == Ecore_X_Randr_None))
+ return EINA_FALSE;
+
+ if (!_ecore_x_randr_crtc_validate(root, crtc_r1) ||
+ (!(crtc_r1 != crtc_r2) &&
+ !_ecore_x_randr_crtc_validate(root, crtc_r2)))
+ return EINA_FALSE;
+
+ ecore_x_randr_crtc_geometry_get(root,
+ crtc_r1,
+ &r1_geo.x,
+ &r1_geo.y,
+ &r1_geo.w,
+ &r1_geo.h);
+ ecore_x_randr_crtc_geometry_get(root,
+ crtc_r2,
+ &r2_geo.x,
+ &r2_geo.y,
+ &r2_geo.w,
+ &r2_geo.h);
+ ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max);
+ ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
+
+ switch (policy)
+ {
+ case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT:
+ //set r1 right of r2
+ x_n = r2_geo.x + r2_geo.w;
+
+ switch (alignment)
+ {
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
+ y_n = Ecore_X_Randr_Unset;
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
+ y_n =
+ ((int)(((double)r2_geo.h /
+ 2.0) + (double)r2_geo.y - ((double)r1_geo.h / 2.0)));
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
+ y_n = ((int)((double)ch / 2.0) - ((double)r1_geo.h / 2.0));
+ break;
+ }
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_LEFT:
+ //set r1 left of r2
+ x_n = r2_geo.x - r1_geo.w;
+
+ switch (alignment)
+ {
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
+ y_n = Ecore_X_Randr_Unset;
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
+ y_n =
+ ((int)(((double)r2_geo.h /
+ 2.0) + r2_geo.y - ((double)r1_geo.h / 2.0)));
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
+ y_n = ((int)(((double)ch / 2.0) - ((double)r1_geo.h / 2.0)));
+ break;
+ }
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_BELOW:
+ //set r1 below r2
+ y_n = r2_geo.y + r2_geo.h;
+
+ switch (alignment)
+ {
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
+ x_n = Ecore_X_Randr_Unset;
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
+ x_n =
+ ((int)((((double)r2_geo.x +
+ (double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0)));
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
+ x_n = ((int)((double)cw / 2.0));
+ break;
+ }
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE:
+ y_n = r2_geo.y - r1_geo.h;
+
+ //set r1 above r2
+ switch (alignment)
+ {
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE:
+ x_n = Ecore_X_Randr_Unset;
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL:
+ x_n =
+ ((int)((((double)r2_geo.x +
+ (double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0)));
+ break;
+
+ case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR:
+ x_n = ((int)((double)cw / 2.0));
+ break;
+ }
+ break;
+
+ case ECORE_X_RANDR_OUTPUT_POLICY_CLONE:
+ return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y);
+
+ /* entire cloning (including modesetting)
+ //all outputs of crtc1 capable of crtc2's current mode?
+ r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2);
+ if (!(r1_outputs =
+ ecore_x_randr_crtc_outputs_get(root, crtc_r1,
+ &r1_noutputs)) ||
+ (r1_noutputs == 0))
+ return EINA_FALSE;
+
+ for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++)
+ {
+ if (!(r1_modes =
+ ecore_x_randr_output_modes_get(root, r1_outputs[i],
+ &r1_nmodes, NULL)))
+ {
+ free(r1_outputs);
+ return EINA_FALSE;
+ }
+
+ for (j = 0; j < r1_nmodes; j++)
+ {
+ ecore_x_randr_mode_size_get(root,
+ r1_modes[j],
+ &mode_w,
+ &mode_h);
+ if ((mode_w == r2_geo.w) && (mode_h == r2_geo.h))
+ {
+ r1_mode = r1_modes[j];
+ ++outputs_mode_found;
+ free(r1_modes);
+ r1_modes = NULL;
+ break;
+ }
+ }
+ if (r1_modes)
+ free(r1_modes);
+
+ if (outputs_mode_found <= i)
+ {
+ //an output doesn't support the set mode, cancel!
+ free(r1_outputs);
+ return EINA_FALSE;
+ }
+ }
+ free (r1_outputs);
+ //CRTC 1's outputs support a mode of same geometry as CRTC 2.
+ ret =
+ (ecore_x_randr_crtc_mode_set(root, crtc_r1, Ecore_X_Randr_None,
+ Ecore_X_Randr_None,
+ r1_mode) &&
+ ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y));
+ return ret;
+ */
+
+ /* entire cloning on same CRTC
+ //all outputs of crtc1 capable of crtc2's current mode?
+ r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2);
+ if (!(r1_outputs =
+ ecore_x_randr_crtc_outputs_get(root, crtc_r1,
+ &r1_noutputs)) ||
+ (r1_noutputs == 0))
+ return EINA_FALSE;
+
+ for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++)
+ {
+ if (!(r1_modes =
+ ecore_x_randr_output_modes_get(root, r1_outputs[i],
+ &r1_nmodes, NULL)))
+ {
+ free(r1_outputs);
+ return EINA_FALSE;
+ }
+
+ for (j = 0; j < r1_nmodes; j++)
+ {
+ if (r1_modes[j] == r2_mode)
+ {
+ ++outputs_mode_found;
+ free(r1_modes);
+ r1_modes = NULL;
+ break;
+ }
+ }
+ if (r1_modes)
+ free(r1_modes);
+
+ if (outputs_mode_found <= i)
+ {
+ //an output doesn't support the set mode, cancel!
+ free(r1_outputs);
+ return EINA_FALSE;
+ }
+ }
+ //check whether crtc r2 can use all outputs of r1.
+ if (!(r2_outputs =
+ ecore_x_randr_crtc_possible_outputs_get(root, crtc_r2,
+ &r2_noutputs)) ||
+ (r2_noutputs == 0))
+ {
+ free(r1_outputs);
+ return EINA_FALSE;
+ }
+
+ for (i = 0; i < r1_noutputs; i++)
+ {
+ for (j = 0; j < r2_noutputs; )
+ {
+ if (r1_outputs[i] == r2_outputs[j])
+ break;
+
+ j++;
+ }
+ if (j == r2_noutputs)
+ {
+ //didn't find the output!
+ free (r1_outputs);
+ free (r2_outputs);
+ return EINA_FALSE;
+ }
+ }
+
+ //apparently crtc2 supports all outputs of r1
+ //TODO: check with the compatible list of outputs (property in RR1.3)
+ r2_r1_outputs =
+ malloc(sizeof(Ecore_X_Randr_Output) * (r1_noutputs + r2_noutputs));
+ for (i = 0; i < r1_noutputs; i++)
+ {
+ r2_r1_outputs[i] = r1_outputs[i];
+ }
+ free(r1_outputs);
+ for (; i < r2_noutputs; i++)
+ {
+ r2_r1_outputs[i] = r2_outputs[i];
+ }
+ free(r2_outputs);
+ ret =
+ ecore_x_randr_crtc_mode_set(root, crtc_r2, r2_r1_outputs,
+ (r1_noutputs + r1_noutputs), r2_mode);
+ free (r2_r1_outputs);
+ return ret;
+ */
+ case ECORE_X_RANDR_OUTPUT_POLICY_NONE:
+ break;
+ default:
+ return EINA_FALSE;
+ }
+ if ((x_n == r1_geo.x) && (y_n == r1_geo.x))
+ return EINA_TRUE;
+
+ //out of possible bounds?
+ if (((y_n + r1_geo.h) > h_max) || ((x_n + r1_geo.w) > w_max))
+ return EINA_FALSE;
+
+ return ecore_x_randr_crtc_pos_set(root, crtc_r1, x_n, y_n);
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/*
+ * @brief Add given mode to given output.
+ *
+ * @param output The output the mode is added to.
+ * @param mode The mode added to the output.
+ * @return @c EINA_FALSE if output or mode equal Ecore_X_Randr_None, else
+ * @c EINA_TRUE.
+ * Additionally, if xcb backend is used, the success of the addition is
+ * reported back directly.
+ * @since 1.2.0
+ */
+EAPI Eina_Bool
+ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+
+ if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None))
+ return EINA_FALSE;
+
+ XRRAddOutputMode(_ecore_x_disp, output, mode);
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/*
+ * @brief delete given mode from given output
+ * @param output the output the mode is removed from
+ * @param mode the mode removed from the output
+ * @since 1.2.0
+ */
+EAPI void
+ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output,
+ Ecore_X_Randr_Mode mode)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+
+ if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None))
+ return;
+
+ XRRDeleteOutputMode(_ecore_x_disp, output, mode);
+#else
+ return;
+#endif
+}
+
+EAPI Ecore_X_Randr_Mode *
+ecore_x_randr_output_modes_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num,
+ int *npreferred)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ Ecore_X_Randr_Mode *modes = NULL;
+
+ if ((output != Ecore_X_Randr_None)
+ && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
+ && (output_info =
+ XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output)))
+ {
+ if ((modes = malloc(sizeof(Ecore_X_Randr_Mode) * output_info->nmode)))
+ {
+ int i = 0;
+
+ if (num) *num = output_info->nmode;
+ if (npreferred) *npreferred = output_info->npreferred;
+
+ for (i = 0; i < output_info->nmode; i++)
+ modes[i] = output_info->modes[i];
+ }
+ }
+
+ if (output_info)
+ XRRFreeOutputInfo(output_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return modes;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Ecore_X_Randr_Crtc *
+ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ Ecore_X_Randr_Crtc *crtcs = NULL;
+
+ if ((output != Ecore_X_Randr_None))
+ {
+ if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
+ {
+ if ((crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc)))
+ {
+ memcpy(crtcs, output_info->crtcs, (sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc));
+ if (num) *num = output_info->ncrtc;
+ }
+ XRRFreeOutputInfo(output_info);
+ }
+ XRRFreeScreenResources(res);
+ }
+ }
+ return crtcs;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+/**
+ * @brief gets the the outputs which might be used simultenously on the same
+ * CRTC.
+ * @param root window that this information should be queried for.
+ * @param output the output which's clones we concern
+ * @param num number of possible clones
+ */
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_output_clones_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ Ecore_X_Randr_Output *outputs = NULL;
+
+ if ((output != Ecore_X_Randr_None))
+ {
+ if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
+ {
+ if ((outputs = malloc(sizeof(Ecore_X_Randr_Output) * output_info->nclone)))
+ {
+ memcpy(outputs, output_info->clones, (sizeof(Ecore_X_Randr_Output) * output_info->nclone));
+ if (num) *num = output_info->nclone;
+ }
+ XRRFreeOutputInfo(output_info);
+ }
+ XRRFreeScreenResources(res);
+ }
+ }
+ return outputs;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+EAPI Ecore_X_Randr_Crtc
+ecore_x_randr_output_crtc_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(Ecore_X_Randr_None);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None;
+
+ if ((output != Ecore_X_Randr_None))
+ {
+ if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
+ {
+ ret = output_info->crtc;
+ XRRFreeOutputInfo(output_info);
+ }
+ XRRFreeScreenResources(res);
+ }
+ }
+
+ return ret;
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+/**
+ * @brief gets the given output's name as reported by X
+ * @param root the window which's screen will be queried
+ * @param output The output for which the name will be reported.
+ * @param len length of returned c-string.
+ * @return name of the output as reported by X
+ */
+EAPI char *
+ecore_x_randr_output_name_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *len)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ char *ret = NULL;
+
+ if ((output != Ecore_X_Randr_None)
+ && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
+ && (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
+ {
+ /*
+ * Actually the below command is correct, but due to a bug in libXrandr
+ * it doesn't work. Therefore we stick with strlen().
+ * Replace the line below with the following once this bug is
+ * fixed within libXrandr.
+ *
+ * *len = output_info->nameLen;
+ *
+ */
+ if ((ret = strdup(output_info->name)) && len)
+ *len = strlen(ret);
+
+ XRRFreeOutputInfo(output_info);
+ }
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * @brief gets the width and hight of a given mode
+ * @param mode the mode which's size is to be looked up
+ * @param w width of given mode in px
+ * @param h height of given mode in px
+ */
+EAPI void
+ecore_x_randr_mode_size_get(Ecore_X_Window root,
+ Ecore_X_Randr_Mode mode,
+ int *w,
+ int *h)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ XRRScreenResources *res = NULL;
+ int i;
+
+ if ((mode != Ecore_X_Randr_None)
+ && (w || h)
+ && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ for (i = 0; i < res->nmode; i++)
+ {
+ if (res->modes[i].id == mode)
+ {
+ if (w)
+ *w = res->modes[i].width;
+
+ if (h)
+ *h = res->modes[i].height;
+
+ break;
+ }
+ }
+ }
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+#endif
+}
+
+/**
+ * @brief gets the EDID information of an attached output if available.
+ * Note that this information is not to be compared using ordinary string
+ * comparison functions, since it includes 0-bytes.
+ * @param root window this information should be queried from
+ * @param output the XID of the output
+ * @param length length of the byte-array. If NULL, request will fail.
+ */
+EAPI unsigned char *
+ecore_x_randr_output_edid_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ unsigned long *length)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(NULL);
+ Atom name = XInternAtom (_ecore_x_disp, RANDR_PROPERTY_EDID, False);
+ unsigned char *prop_data, *ret = NULL;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ Atom actual_type;
+
+ if (!length || !_ecore_x_randr_output_validate(root, output))
+ return NULL;
+
+ if (XRRGetOutputProperty (_ecore_x_disp, output, name,
+ 0, 100, False, False,
+ AnyPropertyType,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop_data) == Success)
+ {
+ if (actual_type == XA_INTEGER && actual_format == 8)
+ {
+ if ((ret = malloc(nitems * sizeof(unsigned char))))
+ {
+ if (length &&
+ (memcpy(ret, prop_data, (nitems * sizeof(unsigned char)))))
+ *length = nitems;
+
+ return ret;
+ }
+ }
+ }
+
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+EAPI Ecore_X_Randr_Connection_Status
+ecore_x_randr_output_connection_status_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN);
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+ Ecore_X_Randr_Connection_Status ret =
+ ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+
+ if ((output != Ecore_X_Randr_None)
+ && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))
+ && (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output)))
+ {
+ ret = output_info->connection;
+ }
+
+ if (output_info)
+ XRRFreeOutputInfo(output_info);
+
+ if (res)
+ XRRFreeScreenResources(res);
+
+ return ret;
+#else
+ return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN;
+#endif
+}
+
+EAPI void
+ecore_x_randr_output_size_mm_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ int *w_mm,
+ int *h_mm)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ XRRScreenResources *res = NULL;
+ XRROutputInfo *output_info = NULL;
+
+ if ((output != Ecore_X_Randr_None)
+ && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ {
+ if ((output_info =
+ XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output)))
+ {
+ if (w_mm)
+ *w_mm = output_info->mm_width;
+
+ if (h_mm)
+ *h_mm = output_info->mm_height;
+
+ XRRFreeOutputInfo(output_info);
+ }
+
+ XRRFreeScreenResources(res);
+ }
+
+#endif
+}
+
+EAPI Eina_Bool
+ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root,
+ const Ecore_X_Randr_Crtc *not_moved,
+ int nnot_moved,
+ int dx,
+ int dy)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Randr_Crtc *crtcs_to_be_moved = NULL;
+ XRRScreenResources *res = NULL;
+ int i, j, k, n;
+ Eina_Bool ret;
+
+ if ((nnot_moved <= 0) || (!not_moved)
+ || !_ecore_x_randr_root_validate(root)
+ || !(res =
+ _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ return EINA_FALSE;
+
+ n = (res->ncrtc - nnot_moved);
+ if ((crtcs_to_be_moved = malloc(sizeof(Ecore_X_Randr_Crtc) * n)))
+ {
+ for (i = 0, k = 0; (i < res->ncrtc) && (k < n); i++)
+ {
+ for (j = 0; j < nnot_moved; j++)
+ {
+ if (res->crtcs[i] == not_moved[j])
+ break;
+ }
+ if (j == nnot_moved)
+ //crtcs[i] is not in the 'not to move'-list
+ crtcs_to_be_moved[k++] = res->crtcs[i];
+ }
+ }
+
+ XRRFreeScreenResources(res);
+ ret = ecore_x_randr_move_crtcs(root, crtcs_to_be_moved, n, dx, dy);
+ free(crtcs_to_be_moved);
+ return ret;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/*
+ * @brief Move given CRTCs belonging to the given root window's screen dx/dy
+ * pixels relative to their current position. The screen size will be
+ * automatically adjusted if necessary and possible.
+ *
+ * @param root Window which's screen's resources are used.
+ * @param crtcs List of CRTCs to be moved.
+ * @param ncrtc Number of CRTCs in array.
+ * @param dx Amount of pixels the CRTCs should be moved in x direction.
+ * @param dy Amount of pixels the CRTCs should be moved in y direction.
+ * @return @c EINA_TRUE if all crtcs could be moved successfully.
+ */
+EAPI Eina_Bool
+ecore_x_randr_move_crtcs(Ecore_X_Window root,
+ const Ecore_X_Randr_Crtc *crtcs,
+ int ncrtc,
+ int dx,
+ int dy)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ XRRScreenResources *res = NULL;
+ XRRCrtcInfo **crtc_info = NULL;
+ Eina_Bool ret = EINA_TRUE;
+ int i, cw, ch, w_max, h_max, nw, nh;
+
+ crtc_info = alloca(sizeof(XRRCrtcInfo *) * ncrtc);
+ memset(crtc_info, 0, sizeof(XRRCrtcInfo *) * ncrtc);
+ if (_ecore_x_randr_root_validate(root)
+ && (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root)))
+ {
+ ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max);
+ ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL);
+ nw = cw;
+ nh = ch;
+
+ for (i = 0;
+ (i < ncrtc) &&
+ (crtc_info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i]));
+ i++)
+ {
+ if (((crtc_info[i]->x + dx) < 0) ||
+ ((int)(crtc_info[i]->x + crtc_info[i]->width + dx) > w_max)
+ || ((crtc_info[i]->y + dy) < 0) ||
+ ((int)(crtc_info[i]->y + crtc_info[i]->height + dy) > h_max)
+ )
+ goto _ecore_x_randr_move_crtcs_fail_free_crtc_info;
+
+ nw = MAX((int)(crtc_info[i]->x + crtc_info[i]->width + dx), nw);
+ nh = MAX((int)(crtc_info[i]->y + crtc_info[i]->height + dy), nh);
+ }
+ //not out of bounds
+
+ //resize if necessary
+ if (!(((nw > cw) ||
+ (nh > ch)) ||
+ ecore_x_randr_screen_current_size_set(root, nw, nh,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset)))
+ goto _ecore_x_randr_move_crtcs_fail_free_crtc_info;
+
+ //actually move all the crtcs, keep their rotation and mode.
+ for (i = 0; (i < ncrtc) && crtc_info[i]; i++)
+ {
+ if ((crtc_info[i]) &&
+ (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL,
+ Ecore_X_Randr_Unset,
+ (crtc_info[i]->x + dx),
+ (crtc_info[i]->y + dy),
+ crtc_info[i]->mode,
+ crtc_info[i]->rotation)))
+ {
+ ret = EINA_FALSE;
+ break;
+ }
+ }
+ if (i < ncrtc)
+ {
+ //something went wrong, let's try to move the already moved crtcs
+ //back.
+ while ((i--) >= 0)
+ {
+ if (crtc_info[i])
+ ecore_x_randr_crtc_settings_set(root,
+ crtcs[i],
+ NULL,
+ Ecore_X_Randr_Unset,
+ (crtc_info[i]->x - dx),
+ (crtc_info[i]->y - dy),
+ crtc_info[i]->mode,
+ crtc_info[i]->rotation);
+ }
+ }
+
+ for (i = 0; i < ncrtc; i++)
+ {
+ if (crtc_info[i]) XRRFreeCrtcInfo(crtc_info[i]);
+ }
+ }
+
+ XRRFreeScreenResources(res);
+
+ return ret;
+_ecore_x_randr_move_crtcs_fail_free_crtc_info:
+ while (i-- > 0)
+ XRRFreeCrtcInfo(crtc_info[i]);
+ XRRFreeScreenResources(res);
+ return EINA_FALSE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
+/**
+ * @brief removes unused screen space. The most upper left CRTC is set to 0x0
+ * and all other CRTCs dx,dy respectively.
+ * @param root the window's screen which will be reset.
+ */
+EAPI void
+ecore_x_randr_screen_reset(Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ XRRCrtcInfo *crtc_info = NULL;
+ XRRScreenResources *res = NULL;
+ //the 100000 are just a random huge number.
+ int i, dx_min = 100000, dy_min = 100000, w_n = 0, h_n = 0, nenabled_crtcs = 0;
+
+ if (!_ecore_x_randr_root_validate(root) ||
+ !(res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)))
+ return;
+
+ Ecore_X_Randr_Crtc enabled_crtcs[res->ncrtc];
+
+ for (i = 0; i < res->ncrtc; i++)
+ {
+ if (!(crtc_info =
+ XRRGetCrtcInfo(_ecore_x_disp, res,
+ res->crtcs[i])) ||
+ (crtc_info->mode == Ecore_X_Randr_None) ||
+ (crtc_info->mode == Ecore_X_Randr_Unset)
+ || ((crtc_info->noutput == 0)))
+ continue;
+
+ enabled_crtcs[nenabled_crtcs++] = res->crtcs[i];
+
+ if ((int)(crtc_info->x + crtc_info->width) > w_n)
+ w_n = (crtc_info->x + crtc_info->width);
+
+ if ((int)(crtc_info->y + crtc_info->height) > h_n)
+ h_n = (crtc_info->y + crtc_info->height);
+
+ if (crtc_info->x < dx_min)
+ dx_min = crtc_info->x;
+ if (crtc_info->y < dy_min)
+ dy_min = crtc_info->y;
+
+ XRRFreeCrtcInfo(crtc_info);
+ }
+ if ((dx_min > 0) || (dy_min > 0))
+ {
+ if (ecore_x_randr_move_crtcs(root, enabled_crtcs, nenabled_crtcs, -dx_min, -dy_min))
+ {
+ w_n -= dx_min;
+ h_n -= dy_min;
+ }
+ }
+ ecore_x_randr_screen_current_size_set(root,
+ w_n,
+ h_n,
+ Ecore_X_Randr_Unset,
+ Ecore_X_Randr_Unset);
+#endif
+}
+
+/**
+ * @brief Set up the backlight level to the given level.
+ *
+ * @param root The window's screen which will be set.
+ * @param level Of the backlight between @c 0 and @c 1.
+ */
+
+EAPI void
+ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root,
+ double level)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET();
+ Atom _backlight;
+ XRRScreenResources *resources = NULL;
+ Ecore_X_Randr_Output output;
+ int o;
+
+ if ((level < 0) || (level > 1))
+ {
+ ERR("Wrong value for the backlight level. It should be between 0 and 1.");
+ return;
+ }
+
+ /*
+ * To make sure that the _backlight atomic property still exists.
+ */
+ _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
+ if (_backlight == None)
+ {
+ WRN("Backlight setting is not supported on this server or driver");
+ return;
+ }
+
+ /* get the ressources */
+ resources = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root);
+ if (!resources) return;
+
+ for (o = 0; o < resources->noutput; o++)
+ {
+ output = resources->outputs[o];
+ if (ecore_x_randr_output_backlight_level_get(root, output) >= 0)
+ {
+ ecore_x_randr_output_backlight_level_set(root, output, level);
+ }
+ }
+ XRRFreeScreenResources(resources);
+#endif
+}
+
+/*
+ * @brief Check if a backlight is available.
+ * @return Whether a backlight is available.
+ */
+
+EAPI Eina_Bool
+ecore_x_randr_output_backlight_available(void)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(-1);
+ Atom _backlight;
+
+ _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
+
+ return (_backlight == None) ? EINA_FALSE : EINA_TRUE;
+
+#endif
+ return EINA_FALSE;
+}
+
+/*
+ * @brief Get the backlight level of the given output.
+ *
+ * @param root Window which's screen should be queried.
+ * @param output From which the backlight level should be retrieved.
+ * @return The backlight level.
+ */
+
+EAPI double
+ecore_x_randr_output_backlight_level_get(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(-1);
+ Atom actual_type;
+ Atom _backlight;
+ XRRPropertyInfo *info = NULL;
+ double dvalue;
+ int actual_format;
+ long value, max, min;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *prop = NULL;
+
+ /* set backlight variable if not already done */
+
+ _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
+ if (_backlight == None)
+ {
+ ERR("Backlight property is not suppported on this server or driver");
+ return -1;
+ }
+
+ if (!_ecore_x_randr_output_validate(root, output))
+ {
+ ERR("Invalid output");
+ return -1;
+ }
+
+ if (XRRGetOutputProperty(_ecore_x_disp, output, _backlight,
+ 0, 4, False, False, None,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop) != Success)
+ {
+ WRN("Backlight not supported on this output");
+ return -1;
+ }
+
+ if ((actual_type != XA_INTEGER) || (nitems != 1) || (actual_format != 32)) return -1;
+
+ value = *((long *)prop);
+ free (prop);
+
+ /* I have the current value of the backlight */
+ /* Now retrieve the min and max intensities of the output */
+ info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight);
+ if (info)
+ {
+ dvalue = -1;
+ if ((info->range) && (info->num_values == 2))
+ {
+ /* finally convert the current value in the interval [0..1] */
+ min = info->values[0];
+ max = info->values[1];
+ dvalue = ((double)(value - min)) / ((double)(max - min));
+ }
+ free(info);
+ return dvalue;
+ }
+#endif
+ return -1;
+}
+
+/*
+ * @brief Set the backlight level of a given output.
+ *
+ * @param root Window which's screen should be queried.
+ * @param output That should be set.
+ * @param level For which the backlight should be set.
+ * @return @c EINA_TRUE in case of success.
+ */
+
+EAPI Eina_Bool
+ecore_x_randr_output_backlight_level_set(Ecore_X_Window root,
+ Ecore_X_Randr_Output output,
+ double level)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_2_RET(EINA_FALSE);
+ Atom _backlight;
+ XRRPropertyInfo *info = NULL;
+ double min, max, tmp;
+ long new;
+
+ if ((level < 0) || (level > 1))
+ {
+ ERR("Backlight level should be between 0 and 1");
+ return EINA_FALSE;
+ }
+
+ if (!_ecore_x_randr_output_validate(root, output))
+ {
+ ERR("Wrong output value");
+ return EINA_FALSE;
+ }
+
+ _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True);
+ if (_backlight == None)
+ {
+ WRN("Backlight property is not suppported on this server or driver");
+ return EINA_FALSE;
+ }
+
+ info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight);
+ if (info)
+ {
+ if ((info->range) && (info->num_values == 2))
+ {
+ min = info->values[0];
+ max = info->values[1];
+ tmp = (level * (max - min)) + min;
+ new = tmp;
+ if (new > max) new = max;
+ if (new < min) new = min;
+ XRRChangeOutputProperty(_ecore_x_disp, output, _backlight, XA_INTEGER, 32,
+ PropModeReplace, (unsigned char *)&new, 1);
+ XFlush(_ecore_x_disp);
+ }
+ free(info);
+ return EINA_TRUE;
+ }
+#endif
+ return EINA_FALSE;
+}
+
+/*
+ * @brief Get the outputs, which display a certain window.
+ *
+ * @param window Window the displaying outputs shall be found for
+ * @param num The number of outputs displaying the window
+ * @return Array of outputs that display a certain window. @c NULL if no
+ * outputs was found that displays the specified window.
+ */
+
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_window_outputs_get(Ecore_X_Window window,
+ int *num)
+{
+#ifdef ECORE_XRANDR
+ Ecore_X_Window root;
+ Ecore_X_Randr_Crtc *crtcs;
+ Ecore_X_Randr_Output *outputs, *ret = NULL, *tret;
+ int ncrtcs, noutputs, i, nret = 0;
+
+ if (_randr_version < RANDR_1_2) goto _ecore_x_randr_current_output_get_fail;
+
+ root = ecore_x_window_root_get(window);
+ if (!(crtcs = ecore_x_randr_window_crtcs_get(window, &ncrtcs)))
+ goto _ecore_x_randr_current_output_get_fail;
+
+ for (i = 0, nret = 0; i < ncrtcs; i++)
+ {
+
+ outputs = ecore_x_randr_crtc_outputs_get(root, crtcs[i],
+ &noutputs);
+ if (!outputs)
+ goto _ecore_x_randr_current_output_get_fail_free;
+ tret = realloc(ret, ((nret + noutputs) * sizeof(Ecore_X_Randr_Output)));
+ if (!tret) goto _ecore_x_randr_current_output_get_fail_free;
+ ret = tret;
+ memcpy(&ret[nret], outputs, (noutputs * sizeof(Ecore_X_Randr_Output)));
+ nret += noutputs;
+ free(outputs);
+ outputs = NULL;
+ }
+ free(crtcs);
+
+ if (num)
+ *num = nret;
+
+ return ret;
+
+_ecore_x_randr_current_output_get_fail_free:
+ free(outputs);
+ free(crtcs);
+ free(ret);
+_ecore_x_randr_current_output_get_fail:
+#endif
+ if (num) *num = 0;
+ return NULL;
+}
+
+/*
+ * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead.
+ * @brief Get the outputs, which display a certain window.
+ *
+ * @param window Window the displaying outputs shall be found for.
+ * @param num The number of outputs displaying the window.
+ * @return Array of outputs that display a certain window. @c NULL if no
+ * outputs was found that displays the specified window.
+ */
+
+EAPI Ecore_X_Randr_Output *
+ecore_x_randr_current_output_get(Ecore_X_Window window,
+ int *num)
+{
+ return ecore_x_randr_window_outputs_get(window, num);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c b/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c
new file mode 100644
index 0000000000..5bda332a06
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2006-2009 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* Original Author: Adam Jackson <ajax@nwnk.net> */
+/* Heavily modified by: Leif Middelschulte <leif.middelschulte@gmail.com> */
+
+#include "Ecore_X.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+/* TODO:
+ * - see other TODO's within this file.
+ */
+
+#define ECORE_X_RANDR_EDID_VERSION_10 ((1 << 8) | 0)
+#define ECORE_X_RANDR_EDID_VERSION_11 ((1 << 8) | 1)
+#define ECORE_X_RANDR_EDID_VERSION_12 ((1 << 8) | 2)
+#define ECORE_X_RANDR_EDID_VERSION_13 ((1 << 8) | 3)
+#define ECORE_X_RANDR_EDID_VERSION_14 ((1 << 8) | 4)
+
+#define _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER 0x08
+#define _ECORE_X_RANDR_EDID_OFFSET_TYPE 0x14
+#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR 0x12
+#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR 0x13
+#define _ECORE_X_RANDR_EDID_OFFSET_DPMS 0x18
+#define _ECORE_X_RANDR_EDID_OFFSET_COLORSPACE 0x18
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK 0x36
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE 3
+#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT 5
+#define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED 15
+#define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO 14
+
+#define _ECORE_X_RANDR_EDID_MASK_DIGITAL 0x80
+#define _ECORE_X_RANDR_EDID_MASK_DIGITAL_INTERFACE 0x0f
+#define _ECORE_X_RANDR_EDID_MASK_DIGITAL_TMDS_DFP_10 0x01
+#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS 0x18
+#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444 0x10
+#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422 0x08
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED 0xe0
+#define _ECORE_X_RANDR_EDID_MASK_DPMS 0xE0
+#define _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY 0x80
+#define _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND 0x40
+#define _ECORE_X_RANDR_EDID_MASK_DPMS_OFF 0x20
+#define _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE 0x0f
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3 0x80
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9 0x40
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10 0x20
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4 0x10
+#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9 0x08
+
+#define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13
+
+typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred {
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03,
+ ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04
+} Ecore_X_Randr_Edid_Aspect_Ratio_Preferred;
+
+/* Some convenience loops */
+#define _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, extension_block_iter) \
+ for (extension_block_iter = edid; extension_block_iter < (edid + edid_length); extension_block_iter += 128)
+
+#define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \
+ _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, cea_block_iter) \
+ if (cea_block_iter[0] == 0x02)
+
+/* The following macro is to be used with caution as it inherits another loop.
+ * Therefore using a 'break;' statement will lead to continuation in the
+ * inherent 'Extension block'-loop.
+ */
+#define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_DETAILED_BLOCK(edid, edid_length, cea_block_iter, detailed_block_iter) \
+ _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \
+ for (detailed_block_iter = cea_block_iter + cea_block_iter[2]; detailed_block_iter + 18 < cea_block_iter + 127; detailed_block_iter += 18) \
+ if (detailed_block_iter[0])
+
+#define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
+ for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3 * 18)); block += 18)
+
+#define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \
+ _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \
+ if ((block[0] == 0) && (block[1] == 0))
+
+EAPI Eina_Bool
+ecore_x_randr_edid_has_valid_header(unsigned char *edid,
+ unsigned long edid_length)
+{
+ const unsigned char header[] =
+ { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+ if (!edid) return EINA_FALSE;
+ if (edid_length < 8) return EINA_FALSE;
+ if (!memcmp(edid, header, 8)) return EINA_TRUE;
+ return EINA_FALSE;
+}
+
+EAPI int
+ecore_x_randr_edid_version_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) &&
+ (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
+ return (edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) |
+ edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR];
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+}
+
+EAPI int
+ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ if ((edid_length > 0x0b) &&
+ (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
+ return (int)(edid[0x0a] + (edid[0x0b] << 8));
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+}
+
+EAPI int
+ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ if ((edid_length > 0x0f) &&
+ (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
+ return (int)(edid[0x0c] + (edid[0x0d] << 8) +
+ (edid[0x0e] << 16) + (edid[0x0f] << 24));
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+}
+
+EAPI char *
+ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ if ((edid_length > (_ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER + 1)) &&
+ (ecore_x_randr_edid_has_valid_header(edid, edid_length)))
+ {
+ unsigned char *x;
+ char *name;
+
+ x = (edid + _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER);
+ name = malloc(sizeof(char) * 4);
+ if (!name) return NULL;
+ name[0] = ((x[0] & 0x7c) >> 2) + '@';
+ name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
+ name[2] = (x[1] & 0x1f) + '@';
+ name[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] = 0;
+ return name;
+ }
+ return NULL;
+}
+
+EAPI char *
+ecore_x_randr_edid_display_name_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ unsigned char *block = NULL;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc)
+ {
+ char *name, *p;
+ const char *edid_name;
+
+ edid_name = (const char *)block + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
+ name = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
+ if (!name) return NULL;
+ strncpy(name, edid_name, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
+ name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
+ for (p = name; *p; p++)
+ {
+ if ((*p < ' ') || (*p > '~')) *p = 0;
+ }
+ return name;
+ }
+ }
+ return NULL;
+}
+
+EAPI Ecore_X_Randr_Edid_Aspect_Ratio
+ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ unsigned char *block = NULL;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
+ (block[10] == 0x04))
+ {
+ Ecore_X_Randr_Edid_Aspect_Ratio_Preferred preferred_ratio =
+ (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred)
+ ((block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED] &
+ _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED) >> 5);
+ switch (preferred_ratio)
+ {
+ case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3:
+ return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
+
+ case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9:
+ return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
+
+ case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10:
+ return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
+
+ case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4:
+ return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
+
+ case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9:
+ return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
+
+ default:
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ }
+ }
+ }
+ return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+}
+
+EAPI Ecore_X_Randr_Edid_Aspect_Ratio
+ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ Ecore_X_Randr_Edid_Aspect_Ratio ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ unsigned char *block = NULL;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) &&
+ (block[10] == 0x04))
+ {
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3)
+ ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3;
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9)
+ ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9;
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10)
+ ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10;
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4)
+ ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4;
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9)
+ ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9;
+ }
+ }
+ return ret;
+}
+
+EAPI char *
+ecore_x_randr_edid_display_ascii_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ unsigned char *block = NULL;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfe)
+ {
+ char *ascii, *p;
+ const char *edid_ascii = (const char *)block +
+ _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
+ /*
+ * TODO: Two of these in a row, in the third and fourth slots,
+ * seems to be specified by SPWG: http://www.spwg.org/
+ */
+ ascii = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
+ if (!ascii) return NULL;
+ strncpy(ascii, edid_ascii, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
+ ascii[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
+ for (p = ascii; *p; p++)
+ {
+ if ((*p < ' ') || (*p > '~')) *p = 0;
+ }
+ return ascii;
+ }
+ }
+ return NULL;
+}
+
+EAPI char *
+ecore_x_randr_edid_display_serial_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ unsigned char *block = NULL;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL;
+ _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block)
+ {
+ if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xff)
+ {
+ char *serial, *p;
+ const char *edid_serial = (const char *)block +
+ _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT;
+ /*
+ * TODO: Two of these in a row, in the third and fourth slots,
+ * seems to be specified by SPWG: http://www.spwg.org/
+ */
+ serial = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX);
+ if (!serial) return NULL;
+ strncpy(serial, edid_serial, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1));
+ serial[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0;
+ for (p = serial; *p; p++)
+ {
+ if ((*p < ' ') || (*p > '~')) *p = 0;
+ }
+ return serial;
+ }
+ }
+ return NULL;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid,
+ unsigned long edid_length)
+{
+ unsigned char *cea_block_iter = NULL;
+ char sum = 0;
+ int i;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ if (edid_length < 128) return EINA_FALSE;
+
+ /* Check the EDID block itself */
+ for (i = 0; i < 128; i++)
+ sum += edid[i];
+ if (sum) return EINA_FALSE;
+
+ /* Check the cea extension blocks */
+ _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter)
+ {
+ for (i = 0, sum = 0; i < 128; i++)
+ sum += cea_block_iter[i];
+ }
+ if (sum) return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_dpms_available_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
+ _ECORE_X_RANDR_EDID_MASK_DPMS);
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
+ return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
+ _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY);
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
+ return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
+ _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND);
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS)
+ return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] &
+ _ECORE_X_RANDR_EDID_MASK_DPMS_OFF);
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_randr_edid_display_type_digital_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE;
+ return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
+ _ECORE_X_RANDR_EDID_MASK_DIGITAL);
+}
+
+EAPI Ecore_X_Randr_Edid_Display_Colorscheme
+ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ Ecore_X_Randr_Edid_Display_Colorscheme colorscheme = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return colorscheme;
+ if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length))
+ {
+ colorscheme = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4;
+ if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
+ _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444)
+ colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4;
+ if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] &
+ _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422)
+ colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2;
+ }
+ else
+ colorscheme = edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS;
+ return colorscheme;
+}
+
+EAPI Ecore_X_Randr_Edid_Display_Interface_Type
+ecore_x_randr_edid_display_interface_type_get(unsigned char *edid,
+ unsigned long edid_length)
+{
+ Ecore_X_Randr_Edid_Display_Interface_Type type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ int version = ecore_x_randr_edid_version_get(edid, edid_length);
+
+ if (version < ECORE_X_RANDR_EDID_VERSION_13) return type;
+ type = edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] &
+ _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE;
+ if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT)
+ type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE;
+ return type;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_13.c b/src/lib/ecore_x/xlib/ecore_x_randr_13.c
new file mode 100644
index 0000000000..5d1c8e96db
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_randr_13.c
@@ -0,0 +1,68 @@
+/*
+ * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ecore_x_private.h"
+#include "ecore_x_randr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define Ecore_X_Randr_None 0
+#define Ecore_X_Randr_Unset -1
+
+#ifdef ECORE_XRANDR
+
+#define RANDR_1_3 ((1 << 16) | 3)
+#define RANDR_CHECK_1_3_RET(ret) if (_randr_version < RANDR_1_3) \
+ return ret
+
+extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display *
+ dpy,
+ Window
+ window);
+extern int _randr_version;
+#endif
+
+/*
+ * @param root window which's screen should be queried
+ * @return Ecore_X_Randr_Ouptut_Id or - if query failed or none is set - Ecore_X_Randr_None
+ */
+EAPI Ecore_X_Randr_Output
+ecore_x_randr_primary_output_get(Ecore_X_Window root)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_3_RET(Ecore_X_Randr_None);
+ if (!_ecore_x_randr_root_validate(root))
+ return Ecore_X_Randr_None;
+
+ return XRRGetOutputPrimary(_ecore_x_disp, root);
+#else
+ return Ecore_X_Randr_None;
+#endif
+}
+
+/*
+ * @param root window which's screen should be queried
+ * @param output that should be set as given root window's screen primary output
+ */
+EAPI void
+ecore_x_randr_primary_output_set(Ecore_X_Window root,
+ Ecore_X_Randr_Output output)
+{
+#ifdef ECORE_XRANDR
+ RANDR_CHECK_1_3_RET();
+
+ if (_ecore_x_randr_output_validate(root, output))
+ {
+ XRRSetOutputPrimary(_ecore_x_disp, root, output);
+ }
+
+#endif
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_region.c b/src/lib/ecore_x/xlib/ecore_x_region.c
new file mode 100644
index 0000000000..81d7eea49c
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_region.c
@@ -0,0 +1,158 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "ecore_x_private.h"
+
+/*
+ * [x] XCreateRegion
+ * [ ] XPolygonRegion
+ * [x] XSetRegion
+ * [x] XDestroyRegion
+ *
+ * [x] XOffsetRegion
+ * [ ] XShrinkRegion
+ *
+ * [ ] XClipBox
+ * [x] XIntersectRegion
+ * [x] XUnionRegion
+ * [x] XUnionRectWithRegion
+ * [x] XSubtractRegion
+ * [ ] XXorRegion
+ *
+ * [x] XEmptyRegion
+ * [x] XEqualRegion
+ *
+ * [x] XPointInRegion
+ * [x] XRectInRegion
+ */
+
+EAPI Ecore_X_XRegion *
+ecore_x_xregion_new()
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return (Ecore_X_XRegion *)XCreateRegion();
+}
+
+EAPI void
+ecore_x_xregion_free(Ecore_X_XRegion *region)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!region)
+ return;
+
+ XDestroyRegion((Region)region);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_set(Ecore_X_XRegion *region,
+ Ecore_X_GC gc)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XSetRegion(_ecore_x_disp, gc, (Region)region) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI void
+ecore_x_xregion_translate(Ecore_X_XRegion *region,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!region)
+ return;
+
+ /* return value not used */
+ XOffsetRegion((Region)region, x, y);
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_intersect(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XIntersectRegion((Region)r1, (Region)r2, (Region)dst) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_union(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XUnionRegion((Region)r1, (Region)r2, (Region)dst) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_union_rect(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *src,
+ Ecore_X_Rectangle *rect)
+{
+ XRectangle xr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xr.x = rect->x;
+ xr.y = rect->y;
+ xr.width = rect->width;
+ xr.height = rect->height;
+
+ return XUnionRectWithRegion(&xr, (Region)src, (Region)dst) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_subtract(Ecore_X_XRegion *dst,
+ Ecore_X_XRegion *rm,
+ Ecore_X_XRegion *rs)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XSubtractRegion((Region)rm, (Region)rs, (Region)dst) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_is_empty(Ecore_X_XRegion *region)
+{
+ if (!region)
+ return EINA_TRUE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XEmptyRegion((Region)region) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_is_equal(Ecore_X_XRegion *r1,
+ Ecore_X_XRegion *r2)
+{
+ if (!r1 || !r2)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XEqualRegion((Region)r1, (Region)r1) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_point_contain(Ecore_X_XRegion *region,
+ int x,
+ int y)
+{
+ if (!region)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XPointInRegion((Region)region, x, y) ? EINA_TRUE : EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_xregion_rect_contain(Ecore_X_XRegion *region,
+ Ecore_X_Rectangle *rect)
+{
+ if (!region || !rect)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XRectInRegion((Region)region,
+ rect->x,
+ rect->y,
+ rect->width,
+ rect->height) ? EINA_TRUE : EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_screensaver.c b/src/lib/ecore_x/xlib/ecore_x_screensaver.c
new file mode 100644
index 0000000000..3688a44c56
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_screensaver.c
@@ -0,0 +1,204 @@
+/*
+ * Screensaver code
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+static int _screensaver_available = -1;
+
+EAPI Eina_Bool
+ecore_x_screensaver_event_available_get(void)
+{
+ if (_screensaver_available >= 0)
+ return _screensaver_available;
+
+#ifdef ECORE_XSS
+ int _screensaver_major, _screensaver_minor;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _screensaver_major = 1;
+ _screensaver_minor = 0;
+
+ if (XScreenSaverQueryVersion(_ecore_x_disp, &_screensaver_major,
+ &_screensaver_minor))
+ _screensaver_available = 1;
+ else
+ _screensaver_available = 0;
+
+#else /* ifdef ECORE_XSS */
+ _screensaver_available = 0;
+#endif /* ifdef ECORE_XSS */
+ return _screensaver_available;
+}
+
+EAPI int
+ecore_x_screensaver_idle_time_get(void)
+{
+#ifdef ECORE_XSS
+ XScreenSaverInfo *xss;
+ int idle;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xss = XScreenSaverAllocInfo();
+ XScreenSaverQueryInfo(_ecore_x_disp,
+ RootWindow(_ecore_x_disp, DefaultScreen(
+ _ecore_x_disp)), xss);
+ idle = xss->idle / 1000;
+ XFree(xss);
+
+ return idle;
+#else
+ return 0;
+#endif /* ifdef ECORE_XSS */
+}
+
+EAPI void
+ecore_x_screensaver_set(int timeout,
+ int interval,
+ int prefer_blanking,
+ int allow_exposures)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSetScreenSaver(_ecore_x_disp,
+ timeout,
+ interval,
+ prefer_blanking,
+ allow_exposures);
+}
+
+EAPI void
+ecore_x_screensaver_timeout_set(int timeout)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ XSetScreenSaver(_ecore_x_disp, timeout, pint, pblank, pexpo);
+}
+
+EAPI int
+ecore_x_screensaver_timeout_get(void)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ return pto;
+}
+
+EAPI void
+ecore_x_screensaver_blank_set(int blank)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ XSetScreenSaver(_ecore_x_disp, pto, pint, blank, pexpo);
+}
+
+EAPI int
+ecore_x_screensaver_blank_get(void)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ return pblank;
+}
+
+EAPI void
+ecore_x_screensaver_expose_set(int expose)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ XSetScreenSaver(_ecore_x_disp, pto, pint, pblank, expose);
+}
+
+EAPI int
+ecore_x_screensaver_expose_get(void)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ return pexpo;
+}
+
+EAPI void
+ecore_x_screensaver_interval_set(int interval)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ XSetScreenSaver(_ecore_x_disp, pto, interval, pblank, pexpo);
+}
+
+EAPI int
+ecore_x_screensaver_interval_get(void)
+{
+ int pto, pint, pblank, pexpo;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo);
+ return pint;
+}
+
+EAPI void
+ecore_x_screensaver_event_listen_set(Eina_Bool on)
+{
+#ifdef ECORE_XSS
+ Ecore_X_Window root;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ root = DefaultRootWindow(_ecore_x_disp);
+ if (on)
+ XScreenSaverSelectInput(_ecore_x_disp, root,
+ ScreenSaverNotifyMask | ScreenSaverCycle);
+ else
+ XScreenSaverSelectInput(_ecore_x_disp, root, 0);
+#else
+ return;
+ on = EINA_FALSE;
+#endif /* ifdef ECORE_XSS */
+}
+
+
+EAPI Eina_Bool
+ecore_x_screensaver_custom_blanking_enable(void)
+{
+#ifdef ECORE_XSS
+ XSetWindowAttributes attr;
+
+ XScreenSaverSetAttributes(_ecore_x_disp,
+ DefaultRootWindow(_ecore_x_disp),
+ -9999, -9999, 1, 1, 0,
+ CopyFromParent, InputOnly, CopyFromParent,
+ 0, &attr);
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XSS */
+}
+
+EAPI Eina_Bool
+ecore_x_screensaver_custom_blanking_disable(void)
+{
+#ifdef ECORE_XSS
+ XScreenSaverUnsetAttributes(_ecore_x_disp,
+ DefaultRootWindow(_ecore_x_disp));
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XSS */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_selection.c b/src/lib/ecore_x/xlib/ecore_x_selection.c
new file mode 100644
index 0000000000..3e1d2d34a2
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_selection.c
@@ -0,0 +1,1021 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif !defined alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# elif defined _AIX
+# define alloca __alloca
+# elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# elif !defined HAVE_ALLOCA
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+# endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+static Ecore_X_Selection_Intern selections[4];
+static Ecore_X_Selection_Converter *converters = NULL;
+static Ecore_X_Selection_Parser *parsers = NULL;
+
+static int _ecore_x_selection_data_default_free(void *data);
+static void *_ecore_x_selection_parser_files(const char *target,
+ void *data,
+ int size,
+ int format);
+static int _ecore_x_selection_data_files_free(void *data);
+static void *_ecore_x_selection_parser_text(const char *target,
+ void *data,
+ int size,
+ int format);
+static int _ecore_x_selection_data_text_free(void *data);
+static void *_ecore_x_selection_parser_targets(const char *target,
+ void *data,
+ int size,
+ int format);
+static int _ecore_x_selection_data_targets_free(void *data);
+
+#define ECORE_X_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x))
+
+void
+_ecore_x_selection_data_init(void)
+{
+ /* Initialize global data */
+ memset(selections, 0, sizeof(selections));
+
+ /* Initialize converters */
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT,
+ ecore_x_selection_converter_text);
+#ifdef X_HAVE_UTF8_STRING
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING,
+ ecore_x_selection_converter_text);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT,
+ ecore_x_selection_converter_text);
+ ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING,
+ ecore_x_selection_converter_text);
+
+ /* Initialize parsers */
+ ecore_x_selection_parser_add("text/plain",
+ _ecore_x_selection_parser_text);
+ ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING,
+ _ecore_x_selection_parser_text);
+ ecore_x_selection_parser_add("text/uri-list",
+ _ecore_x_selection_parser_files);
+ ecore_x_selection_parser_add("_NETSCAPE_URL",
+ _ecore_x_selection_parser_files);
+ ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS,
+ _ecore_x_selection_parser_targets);
+}
+
+void
+_ecore_x_selection_shutdown(void)
+{
+ Ecore_X_Selection_Converter *cnv;
+ Ecore_X_Selection_Parser *prs;
+
+ /* free the selection converters */
+ cnv = converters;
+ while (cnv)
+ {
+ Ecore_X_Selection_Converter *tmp;
+
+ tmp = cnv->next;
+ free(cnv);
+ cnv = tmp;
+ }
+ converters = NULL;
+
+ /* free the selection parsers */
+ prs = parsers;
+ while (prs)
+ {
+ Ecore_X_Selection_Parser *tmp;
+
+ tmp = prs;
+ prs = prs->next;
+ free(tmp->target);
+ free(tmp);
+ }
+ parsers = NULL;
+}
+
+Ecore_X_Selection_Intern *
+_ecore_x_selection_get(Ecore_X_Atom selection)
+{
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ return &selections[0];
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ return &selections[1];
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ return &selections[2];
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ return &selections[3];
+ else
+ return NULL;
+}
+
+Eina_Bool
+_ecore_x_selection_set(Window w,
+ const void *data,
+ int size,
+ Ecore_X_Atom selection)
+{
+ int in;
+ unsigned char *buf = NULL;
+
+ XSetSelectionOwner(_ecore_x_disp, selection, w, _ecore_x_event_last_time);
+ if (XGetSelectionOwner(_ecore_x_disp, selection) != w)
+ return EINA_FALSE;
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ in = 0;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ in = 1;
+ else if (selection == ECORE_X_ATOM_SELECTION_XDND)
+ in = 2;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ in = 3;
+ else
+ return EINA_FALSE;
+
+ if (data)
+ {
+ selections[in].win = w;
+ selections[in].selection = selection;
+ selections[in].length = size;
+ selections[in].time = _ecore_x_event_last_time;
+
+ buf = malloc(size);
+ if (!buf) return EINA_FALSE;
+ memcpy(buf, data, size);
+ selections[in].data = buf;
+ }
+ else if (selections[in].data)
+ {
+ free(selections[in].data);
+ memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data));
+ }
+
+ return EINA_TRUE;
+}
+
+/**
+ * Claim ownership of the PRIMARY selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_primary_set(Ecore_X_Window w,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_PRIMARY);
+}
+
+/**
+ * Release ownership of the primary selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ *
+ */
+EAPI Eina_Bool
+ecore_x_selection_primary_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY);
+}
+
+/**
+ * Claim ownership of the SECONDARY selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_secondary_set(Ecore_X_Window w,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(w,
+ data,
+ size,
+ ECORE_X_ATOM_SELECTION_SECONDARY);
+}
+
+/**
+ * Release ownership of the secondary selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ *
+ */
+EAPI Eina_Bool
+ecore_x_selection_secondary_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(None,
+ NULL,
+ 0,
+ ECORE_X_ATOM_SELECTION_SECONDARY);
+}
+
+/**
+ * Claim ownership of the XDND selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ */
+EAPI Eina_Bool
+ecore_x_selection_xdnd_set(Ecore_X_Window w,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_XDND);
+}
+
+/**
+ * Release ownership of the XDND selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ *
+ */
+EAPI Eina_Bool
+ecore_x_selection_xdnd_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_XDND);
+}
+
+/**
+ * Claim ownership of the CLIPBOARD selection and set its data.
+ * @param w The window to which this selection belongs
+ * @param data The data associated with the selection
+ * @param size The size of the data buffer in bytes
+ * @return Returns 1 if the ownership of the selection was successfully
+ * claimed, or 0 if unsuccessful.
+ *
+ * Get the converted data from a previous CLIPBOARD selection
+ * request. The buffer must be freed when done with.
+ */
+EAPI Eina_Bool
+ecore_x_selection_clipboard_set(Ecore_X_Window w,
+ const void *data,
+ int size)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(w,
+ data,
+ size,
+ ECORE_X_ATOM_SELECTION_CLIPBOARD);
+}
+
+/**
+ * Release ownership of the clipboard selection
+ * @return Returns 1 if the selection was successfully cleared,
+ * or 0 if unsuccessful.
+ *
+ */
+EAPI Eina_Bool
+ecore_x_selection_clipboard_clear(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_selection_set(None,
+ NULL,
+ 0,
+ ECORE_X_ATOM_SELECTION_CLIPBOARD);
+}
+
+Ecore_X_Atom
+_ecore_x_selection_target_atom_get(const char *target)
+{
+ Ecore_X_Atom x_target;
+
+ if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
+ x_target = ECORE_X_ATOM_TEXT;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
+ x_target = ECORE_X_ATOM_COMPOUND_TEXT;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
+ x_target = ECORE_X_ATOM_STRING;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
+ x_target = ECORE_X_ATOM_UTF8_STRING;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME))
+ x_target = ECORE_X_ATOM_FILE_NAME;
+ else
+ x_target = ecore_x_atom_get(target);
+
+ return x_target;
+}
+
+char *
+_ecore_x_selection_target_get(Ecore_X_Atom target)
+{
+ /* FIXME: Should not return mem allocated with strdup or X mixed,
+ * one should use free to free, the other XFree */
+ if (target == ECORE_X_ATOM_FILE_NAME)
+ return strdup(ECORE_X_SELECTION_TARGET_FILENAME);
+ else if (target == ECORE_X_ATOM_STRING)
+ return strdup(ECORE_X_SELECTION_TARGET_STRING);
+ else if (target == ECORE_X_ATOM_UTF8_STRING)
+ return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING);
+ else if (target == ECORE_X_ATOM_TEXT)
+ return strdup(ECORE_X_SELECTION_TARGET_TEXT);
+ else
+ return XGetAtomName(_ecore_x_disp, target);
+}
+
+static void
+_ecore_x_selection_request(Ecore_X_Window w,
+ Ecore_X_Atom selection,
+ const char *target_str)
+{
+ Ecore_X_Atom target, prop;
+
+ target = _ecore_x_selection_target_atom_get(target_str);
+
+ if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
+ prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
+ prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
+ else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
+ prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
+ else
+ return;
+
+ XConvertSelection(_ecore_x_disp, selection, target, prop,
+ w, CurrentTime);
+}
+
+EAPI void
+ecore_x_selection_primary_request(Ecore_X_Window w,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_PRIMARY, target);
+}
+
+EAPI void
+ecore_x_selection_secondary_request(Ecore_X_Window w,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_SECONDARY, target);
+}
+
+EAPI void
+ecore_x_selection_xdnd_request(Ecore_X_Window w,
+ const char *target)
+{
+ Ecore_X_Atom atom;
+ Ecore_X_DND_Target *_target;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _target = _ecore_x_dnd_target_get();
+ atom = _ecore_x_selection_target_atom_get(target);
+ XConvertSelection(_ecore_x_disp, ECORE_X_ATOM_SELECTION_XDND, atom,
+ ECORE_X_ATOM_SELECTION_PROP_XDND, w,
+ _target->time);
+}
+
+EAPI void
+ecore_x_selection_clipboard_request(Ecore_X_Window w,
+ const char *target)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_CLIPBOARD, target);
+}
+
+EAPI void
+ecore_x_selection_converter_atom_add(Ecore_X_Atom target,
+ Eina_Bool (*func)(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *ttype,
+ int *tsize))
+{
+ Ecore_X_Selection_Converter *cnv;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ cnv = converters;
+ if (converters)
+ {
+ while (1)
+ {
+ if (cnv->target == target)
+ {
+ cnv->convert = func;
+ return;
+ }
+
+ if (cnv->next)
+ cnv = cnv->next;
+ else
+ break;
+ }
+
+ cnv->next = calloc(1, sizeof(Ecore_X_Selection_Converter));
+ if (!cnv->next) return;
+ cnv = cnv->next;
+ }
+ else
+ {
+ converters = calloc(1, sizeof(Ecore_X_Selection_Converter));
+ if (!converters) return;
+ cnv = converters;
+ }
+
+ cnv->target = target;
+ cnv->convert = func;
+}
+
+EAPI void
+ecore_x_selection_converter_add(char *target,
+ Eina_Bool (*func)(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *,
+ int *))
+{
+ Ecore_X_Atom x_target;
+
+ if (!func || !target)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ x_target = _ecore_x_selection_target_atom_get(target);
+
+ ecore_x_selection_converter_atom_add(x_target, func);
+}
+
+EAPI void
+ecore_x_selection_converter_atom_del(Ecore_X_Atom target)
+{
+ Ecore_X_Selection_Converter *cnv, *prev_cnv;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ prev_cnv = NULL;
+ cnv = converters;
+
+ while (cnv)
+ {
+ if (cnv->target == target)
+ {
+ if (prev_cnv)
+ prev_cnv->next = cnv->next;
+ else
+ {
+ converters = cnv->next; /* This was the first converter */
+ }
+
+ free(cnv);
+
+ return;
+ }
+
+ prev_cnv = cnv;
+ cnv = cnv->next;
+ }
+}
+
+EAPI void
+ecore_x_selection_converter_del(char *target)
+{
+ Ecore_X_Atom x_target;
+
+ if (!target)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ x_target = _ecore_x_selection_target_atom_get(target);
+ ecore_x_selection_converter_atom_del(x_target);
+}
+
+EAPI Eina_Bool
+ecore_x_selection_notify_send(Ecore_X_Window requestor,
+ Ecore_X_Atom selection,
+ Ecore_X_Atom target,
+ Ecore_X_Atom property,
+ Ecore_X_Time tim)
+{
+ XEvent xev;
+ XSelectionEvent xnotify;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xnotify.type = SelectionNotify;
+ xnotify.display = _ecore_x_disp;
+ xnotify.requestor = requestor;
+ xnotify.selection = selection;
+ xnotify.target = target;
+ xnotify.property = property;
+ xnotify.time = tim;
+ xnotify.send_event = True;
+ xnotify.serial = 0;
+
+ xev.xselection = xnotify;
+ return (XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? EINA_TRUE : EINA_FALSE;
+}
+
+/* Locate and run conversion callback for specified selection target */
+EAPI Eina_Bool
+ecore_x_selection_convert(Ecore_X_Atom selection,
+ Ecore_X_Atom target,
+ void **data_ret,
+ int *size,
+ Ecore_X_Atom *targtype,
+ int *typesize)
+{
+ Ecore_X_Selection_Intern *sel;
+ Ecore_X_Selection_Converter *cnv;
+ void *data;
+ char *tgt_str;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ sel = _ecore_x_selection_get(selection);
+ tgt_str = _ecore_x_selection_target_get(target);
+
+ for (cnv = converters; cnv; cnv = cnv->next)
+ {
+ if (cnv->target == target)
+ {
+ int r;
+ r = cnv->convert(tgt_str, sel->data, sel->length, &data, size,
+ targtype, typesize);
+ free(tgt_str);
+ if (r)
+ {
+ *data_ret = data;
+ return r;
+ }
+ else
+ return EINA_FALSE;
+ }
+ }
+
+ /* ICCCM says "If the selection cannot be converted into a form based on the target (and parameters, if any), the owner should refuse the SelectionRequest as previously described." */
+ return EINA_FALSE;
+
+ /* Default, just return the data
+ * data_ret = malloc(sel->length);
+ memcpy(*data_ret, sel->data, sel->length);
+ free(tgt_str);
+ return 1;
+ */
+}
+
+/* TODO: We need to work out a mechanism for automatic conversion to any requested
+ * locale using Ecore_Txt functions */
+/* Converter for standard non-utf8 text targets */
+EAPI Eina_Bool
+ecore_x_selection_converter_text(char *target,
+ void *data,
+ int size,
+ void **data_ret,
+ int *size_ret,
+ Ecore_X_Atom *targprop EINA_UNUSED,
+ int *s EINA_UNUSED)
+{
+ XTextProperty text_prop;
+ char *mystr;
+ XICCEncodingStyle style;
+
+ if (!data || !size)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
+ style = XTextStyle;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
+ style = XCompoundTextStyle;
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
+ style = XStringStyle;
+
+#ifdef X_HAVE_UTF8_STRING
+ else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
+ style = XUTF8StringStyle;
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ else
+ return EINA_FALSE;
+
+ mystr = alloca(size + 1);
+ memcpy(mystr, data, size);
+ mystr[size] = '\0';
+
+#ifdef X_HAVE_UTF8_STRING
+ if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
+ &text_prop) == Success)
+ {
+ int bufsize = strlen((char *)text_prop.value) + 1;
+ *data_ret = malloc(bufsize);
+ if (!*data_ret)
+ {
+ return EINA_FALSE;
+ }
+ memcpy(*data_ret, text_prop.value, bufsize);
+ *size_ret = bufsize;
+ XFree(text_prop.value);
+ return EINA_TRUE;
+ }
+
+#else /* ifdef X_HAVE_UTF8_STRING */
+ if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
+ &text_prop) == Success)
+ {
+ int bufsize = strlen(text_prop.value) + 1;
+ *data_ret = malloc(bufsize);
+ if (!*data_ret) return EINA_FALSE;
+ memcpy(*data_ret, text_prop.value, bufsize);
+ *size_ret = bufsize;
+ XFree(text_prop.value);
+ return EINA_TRUE;
+ }
+
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ else
+ {
+ return EINA_TRUE;
+ }
+}
+
+EAPI void
+ecore_x_selection_parser_add(const char *target,
+ void *(*func)(const char *target, void *data,
+ int size,
+ int format))
+{
+ Ecore_X_Selection_Parser *prs;
+
+ if (!target)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ prs = parsers;
+ if (parsers)
+ {
+ while (prs->next)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ prs->parse = func;
+ return;
+ }
+
+ prs = prs->next;
+ }
+
+ prs->next = calloc(1, sizeof(Ecore_X_Selection_Parser));
+ if (!prs->next) return;
+ prs = prs->next;
+ }
+ else
+ {
+ parsers = calloc(1, sizeof(Ecore_X_Selection_Parser));
+ if (!parsers) return;
+ prs = parsers;
+ }
+
+ prs->target = strdup(target);
+ prs->parse = func;
+}
+
+EAPI void
+ecore_x_selection_parser_del(const char *target)
+{
+ Ecore_X_Selection_Parser *prs, *prev_prs;
+
+ if (!target)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ prev_prs = NULL;
+ prs = parsers;
+
+ while (prs)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ if (prev_prs)
+ prev_prs->next = prs->next;
+ else
+ {
+ parsers = prs->next; /* This was the first parser */
+ }
+
+ free(prs->target);
+ free(prs);
+
+ return;
+ }
+
+ prev_prs = prs;
+ prs = prs->next;
+ }
+}
+
+/**
+ * Change the owner and last-change time for the specified selection.
+ * @param win The owner of the specified atom.
+ * @param atom The selection atom
+ * @param tim Specifies the time
+ * @since 1.1.0
+ */
+EAPI void
+ecore_x_selection_owner_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Time tim)
+{
+ XSetSelectionOwner(_ecore_x_disp, atom, win, tim);
+}
+
+/**
+ * Return the window that currently owns the specified selection.
+ *
+ * @param atom The specified selection atom.
+ *
+ * @return The window that currently owns the specified selection.
+ * @since 1.1.0
+ */
+EAPI Ecore_X_Window
+ecore_x_selection_owner_get(Ecore_X_Atom atom)
+{
+ return XGetSelectionOwner(_ecore_x_disp, atom);
+}
+
+/* Locate and run conversion callback for specified selection target */
+void *
+_ecore_x_selection_parse(const char *target,
+ void *data,
+ int size,
+ int format)
+{
+ Ecore_X_Selection_Parser *prs;
+ Ecore_X_Selection_Data *sel;
+
+ for (prs = parsers; prs; prs = prs->next)
+ {
+ if (!strcmp(prs->target, target))
+ {
+ sel = prs->parse(target, data, size, format);
+ if (sel) return sel;
+ }
+ }
+
+ /* Default, just return the data */
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data));
+ if (!sel) return NULL;
+ sel->free = _ecore_x_selection_data_default_free;
+ sel->length = size;
+ sel->format = format;
+ sel->data = data;
+ return sel;
+}
+
+static int
+_ecore_x_selection_data_default_free(void *data)
+{
+ Ecore_X_Selection_Data *sel;
+
+ sel = data;
+ free(sel->data);
+ free(sel);
+ return 1;
+}
+
+static void *
+_ecore_x_selection_parser_files(const char *target,
+ void *_data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Files *sel;
+ char *t, *data = _data;
+ int i, is;
+ char *tmp;
+ char **t2;
+
+ if (strcmp(target, "text/uri-list") &&
+ strcmp(target, "_NETSCAPE_URL"))
+ return NULL;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files));
+ if (!sel) return NULL;
+ ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free;
+
+ if (data && data[size - 1])
+ {
+ /* Isn't nul terminated */
+ size++;
+ t = realloc(data, size);
+ if (!t)
+ {
+ free(sel);
+ return NULL;
+ }
+ data = t;
+ data[size - 1] = 0;
+ }
+
+ tmp = malloc(size);
+ if (!tmp)
+ {
+ free(sel);
+ return NULL;
+ }
+ i = 0;
+ is = 0;
+ while ((is < size) && (data[is]))
+ {
+ if ((i == 0) && (data[is] == '#'))
+ for (; ((data[is]) && (data[is] != '\n')); is++) ;
+ else
+ {
+ if ((data[is] != '\r') &&
+ (data[is] != '\n'))
+ tmp[i++] = data[is++];
+ else
+ {
+ while ((data[is] == '\r') || (data[is] == '\n'))
+ is++;
+ tmp[i] = 0;
+ sel->num_files++;
+ t2 = realloc(sel->files, sel->num_files * sizeof(char *));
+ if (t2)
+ {
+ sel->files = t2;
+ sel->files[sel->num_files - 1] = strdup(tmp);
+ }
+ tmp[0] = 0;
+ i = 0;
+ }
+ }
+ }
+ if (i > 0)
+ {
+ tmp[i] = 0;
+ sel->num_files++;
+ t2 = realloc(sel->files, sel->num_files * sizeof(char *));
+ if (t2)
+ {
+ sel->files = t2;
+ sel->files[sel->num_files - 1] = strdup(tmp);
+ }
+ }
+
+ free(tmp);
+ free(data);
+
+ ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES;
+ ECORE_X_SELECTION_DATA(sel)->length = sel->num_files;
+
+ return ECORE_X_SELECTION_DATA(sel);
+}
+
+static int
+_ecore_x_selection_data_files_free(void *data)
+{
+ Ecore_X_Selection_Data_Files *sel;
+ int i;
+
+ sel = data;
+ if (sel->files)
+ {
+ for (i = 0; i < sel->num_files; i++)
+ free(sel->files[i]);
+ free(sel->files);
+ }
+
+ free(sel);
+ return 0;
+}
+
+static void *
+_ecore_x_selection_parser_text(const char *target EINA_UNUSED,
+ void *_data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Text *sel;
+ unsigned char *data = _data;
+ void *t;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text));
+ if (!sel) return NULL;
+ if (data && data[size - 1])
+ {
+ /* Isn't nul terminated */
+ size++;
+ t = realloc(data, size);
+ if (!t)
+ {
+ free(sel);
+ return NULL;
+ }
+ data = t;
+ data[size - 1] = 0;
+ }
+
+ sel->text = (char *)data;
+ ECORE_X_SELECTION_DATA(sel)->length = size;
+ ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT;
+ ECORE_X_SELECTION_DATA(sel)->data = data;
+ ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_text_free;
+ return sel;
+}
+
+static int
+_ecore_x_selection_data_text_free(void *data)
+{
+ Ecore_X_Selection_Data_Text *sel;
+
+ sel = data;
+ free(sel->text);
+ free(sel);
+ return 1;
+}
+
+static void *
+_ecore_x_selection_parser_targets(const char *target EINA_UNUSED,
+ void *data,
+ int size,
+ int format EINA_UNUSED)
+{
+ Ecore_X_Selection_Data_Targets *sel;
+ unsigned long *targets;
+ int i;
+
+ sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets));
+ if (!sel) return NULL;
+ targets = (unsigned long *)data;
+
+ sel->num_targets = size - 2;
+ sel->targets = malloc((size - 2) * sizeof(char *));
+ if (!sel->targets)
+ {
+ free(sel);
+ return NULL;
+ }
+ for (i = 2; i < size; i++)
+ sel->targets[i - 2] = XGetAtomName(_ecore_x_disp, targets[i]);
+
+ ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free;
+ ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS;
+ ECORE_X_SELECTION_DATA(sel)->length = size;
+ ECORE_X_SELECTION_DATA(sel)->data = data;
+ return sel;
+}
+
+static int
+_ecore_x_selection_data_targets_free(void *data)
+{
+ Ecore_X_Selection_Data_Targets *sel;
+ int i;
+
+ sel = data;
+
+ if (sel->targets)
+ {
+ for (i = 0; i < sel->num_targets; i++)
+ XFree(sel->targets[i]);
+ free(sel->targets);
+ }
+
+ free(ECORE_X_SELECTION_DATA(sel)->data);
+ free(sel);
+ return 1;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_sync.c b/src/lib/ecore_x/xlib/ecore_x_sync.c
new file mode 100644
index 0000000000..0c7f546f1a
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_sync.c
@@ -0,0 +1,159 @@
+/*
+ * XSync code
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+EAPI Ecore_X_Sync_Alarm
+ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter)
+{
+ Ecore_X_Sync_Alarm alarm;
+ XSyncAlarmAttributes values;
+ XSyncValue init;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntToValue(&init, 0);
+ XSyncSetCounter(_ecore_x_disp, counter, init);
+
+ values.trigger.counter = counter;
+ values.trigger.value_type = XSyncAbsolute;
+ XSyncIntToValue(&values.trigger.wait_value, 1);
+ values.trigger.test_type = XSyncPositiveComparison;
+
+ XSyncIntToValue(&values.delta, 1);
+
+ values.events = True;
+
+ alarm = XSyncCreateAlarm(_ecore_x_disp,
+ XSyncCACounter |
+ XSyncCAValueType |
+ XSyncCAValue |
+ XSyncCATestType |
+ XSyncCADelta |
+ XSyncCAEvents,
+ &values);
+
+ ecore_x_sync();
+ return alarm;
+}
+
+EAPI Eina_Bool
+ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XSyncDestroyAlarm(_ecore_x_disp, alarm);
+}
+
+EAPI Eina_Bool
+ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter,
+ unsigned int *val)
+{
+ XSyncValue value;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XSyncQueryCounter(_ecore_x_disp, counter, &value))
+ {
+ *val = (unsigned int)XSyncValueLow32(value);
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+EAPI Ecore_X_Sync_Counter
+ecore_x_sync_counter_new(int val)
+{
+ XSyncCounter counter;
+ XSyncValue v;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntToValue(&v, val);
+ counter = XSyncCreateCounter(_ecore_x_disp, v);
+ return counter;
+}
+
+EAPI void
+ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncDestroyCounter(_ecore_x_disp, counter);
+}
+
+EAPI void
+ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter,
+ int by)
+{
+ XSyncValue v;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntToValue(&v, by);
+ XSyncChangeCounter(_ecore_x_disp, counter, v);
+}
+
+EAPI void
+ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter,
+ int val)
+{
+ XSyncWaitCondition cond;
+ XSyncValue v, v2;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncQueryCounter(_ecore_x_disp, counter, &v);
+ XSyncIntToValue(&v, val);
+ XSyncIntToValue(&v2, val + 1);
+ cond.trigger.counter = counter;
+ cond.trigger.value_type = XSyncAbsolute;
+ cond.trigger.wait_value = v;
+ cond.trigger.test_type = XSyncPositiveComparison;
+ cond.event_threshold = v2;
+ XSyncAwait(_ecore_x_disp, &cond, 1);
+// XSync(_ecore_x_disp, False); // dont need this
+}
+
+EAPI void
+ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter,
+ int val)
+{
+ XSyncValue v;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntToValue(&v, val);
+ XSyncSetCounter(_ecore_x_disp, counter, v);
+}
+
+EAPI void
+ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter,
+ int val_hi,
+ unsigned int val_lo)
+{
+ XSyncValue v;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSyncIntsToValue(&v, val_lo, val_hi);
+ XSyncSetCounter(_ecore_x_disp, counter, v);
+}
+
+EAPI Eina_Bool
+ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter,
+ int *val_hi,
+ unsigned int *val_lo)
+{
+ XSyncValue value;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (XSyncQueryCounter(_ecore_x_disp, counter, &value))
+ {
+ *val_lo = (unsigned int)XSyncValueLow32(value);
+ *val_hi = (int)XSyncValueHigh32(value);
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_test.c b/src/lib/ecore_x/xlib/ecore_x_test.c
new file mode 100644
index 0000000000..4eec6b74b3
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_test.c
@@ -0,0 +1,167 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#ifdef ECORE_XTEST
+# include <X11/extensions/XTest.h>
+#endif /* ifdef ECORE_XTEST */
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include <string.h>
+
+EAPI Eina_Bool
+#ifdef ECORE_XTEST
+ecore_x_test_fake_key_down(const char *key)
+#else
+ecore_x_test_fake_key_down(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XTEST
+ KeyCode keycode = 0;
+ KeySym keysym;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ return EINA_FALSE;
+
+ keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+ }
+
+ if (keycode == 0)
+ return EINA_FALSE;
+
+ return XTestFakeKeyEvent(_ecore_x_disp, keycode, 1, 0) ? EINA_TRUE : EINA_FALSE;
+#else /* ifdef ECORE_XTEST */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XTEST */
+}
+
+EAPI Eina_Bool
+#ifdef ECORE_XTEST
+ecore_x_test_fake_key_up(const char *key)
+#else
+ecore_x_test_fake_key_up(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XTEST
+ KeyCode keycode = 0;
+ KeySym keysym;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ return EINA_FALSE;
+
+ keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+ }
+
+ if (keycode == 0)
+ return EINA_FALSE;
+
+ return XTestFakeKeyEvent(_ecore_x_disp, keycode, 0, 0) ? EINA_TRUE : EINA_FALSE;
+#else /* ifdef ECORE_XTEST */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XTEST */
+}
+
+EAPI Eina_Bool
+#ifdef ECORE_XTEST
+ecore_x_test_fake_key_press(const char *key)
+#else
+ecore_x_test_fake_key_press(const char *key EINA_UNUSED)
+#endif
+{
+#ifdef ECORE_XTEST
+ KeyCode keycode = 0;
+ KeySym keysym = 0;
+ int shift = 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!strncmp(key, "Keycode-", 8))
+ keycode = atoi(key + 8);
+ else
+ {
+ keysym = XStringToKeysym(key);
+ if (keysym == NoSymbol)
+ return EINA_FALSE;
+
+ keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+ if (_ecore_x_XKeycodeToKeysym(_ecore_x_disp, keycode, 0) != keysym)
+ {
+ if (_ecore_x_XKeycodeToKeysym(_ecore_x_disp, keycode, 1) == keysym)
+ shift = 1;
+ else
+ keycode = 0;
+ }
+ else
+ shift = 0;
+ }
+
+ if (keycode == 0)
+ {
+ static int mod = 0;
+ KeySym *keysyms;
+ int keycode_min, keycode_max, keycode_num;
+ int i;
+
+ XDisplayKeycodes(_ecore_x_disp, &keycode_min, &keycode_max);
+ keysyms = XGetKeyboardMapping(_ecore_x_disp, keycode_min,
+ keycode_max - keycode_min + 1,
+ &keycode_num);
+ mod = (mod + 1) & 0x7;
+ i = (keycode_max - keycode_min - mod - 1) * keycode_num;
+
+ keysyms[i] = keysym;
+ XChangeKeyboardMapping(_ecore_x_disp, keycode_min, keycode_num,
+ keysyms, (keycode_max - keycode_min));
+ XFree(keysyms);
+ XSync(_ecore_x_disp, False);
+ keycode = keycode_max - mod - 1;
+ }
+
+ if (shift)
+ XTestFakeKeyEvent(_ecore_x_disp,
+ XKeysymToKeycode(_ecore_x_disp, XK_Shift_L), 1, 0);
+
+ XTestFakeKeyEvent(_ecore_x_disp, keycode, 1, 0);
+ XTestFakeKeyEvent(_ecore_x_disp, keycode, 0, 0);
+ if (shift)
+ XTestFakeKeyEvent(_ecore_x_disp,
+ XKeysymToKeycode(_ecore_x_disp, XK_Shift_L), 0, 0);
+
+ return EINA_TRUE;
+#else /* ifdef ECORE_XTEST */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XTEST */
+}
+
+EAPI const char *
+ecore_x_keysym_string_get(int keysym)
+{
+ return XKeysymToString(keysym);
+}
+
+EAPI int
+ecore_x_keysym_keycode_get(const char *keyname)
+{
+ int keycode = 0;
+
+ if (!strncmp(keyname, "Keycode-", 8))
+ keycode = atoi(keyname + 8);
+ else
+ keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(keyname));
+
+ return keycode;
+}
diff --git a/src/lib/ecore_x/xlib/ecore_x_vsync.c b/src/lib/ecore_x/xlib/ecore_x_vsync.c
new file mode 100644
index 0000000000..a316a33c45
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_vsync.c
@@ -0,0 +1,351 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define ECORE_X_VSYNC_DRI2 1
+
+#ifdef ECORE_X_VSYNC_DRI2
+// relevant header bits of dri/drm inlined here to avoid needing external
+// headers to build
+/// drm
+typedef unsigned int drm_magic_t;
+
+typedef enum
+{
+ DRM_VBLANK_ABSOLUTE = 0x00000000,
+ DRM_VBLANK_RELATIVE = 0x00000001,
+ DRM_VBLANK_EVENT = 0x04000000,
+ DRM_VBLANK_FLIP = 0x08000000,
+ DRM_VBLANK_NEXTONMISS = 0x10000000,
+ DRM_VBLANK_SECONDARY = 0x20000000,
+ DRM_VBLANK_SIGNAL = 0x40000000
+}
+drmVBlankSeqType;
+
+typedef struct _drmVBlankReq
+{
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ unsigned long signal;
+} drmVBlankReq;
+
+typedef struct _drmVBlankReply
+{
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+} drmVBlankReply;
+
+typedef union _drmVBlank
+{
+ drmVBlankReq request;
+ drmVBlankReply reply;
+} drmVBlank;
+
+#define DRM_EVENT_CONTEXT_VERSION 2
+
+typedef struct _drmEventContext
+{
+ int version;
+ void (*vblank_handler)(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+ void (*page_flip_handler)(int fd,
+ unsigned int sequence,
+ unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *user_data);
+} drmEventContext;
+
+static int (*sym_drmClose)(int fd) = NULL;
+static int (*sym_drmGetMagic)(int fd,
+ drm_magic_t *magic) = NULL;
+static int (*sym_drmWaitVBlank)(int fd,
+ drmVBlank *vbl) = NULL;
+static int (*sym_drmHandleEvent)(int fd,
+ drmEventContext *evctx) = NULL;
+
+//// dri
+
+static Bool (*sym_DRI2QueryExtension)(Display *display,
+ int *eventBase,
+ int *errorBase) = NULL;
+static Bool (*sym_DRI2QueryVersion)(Display *display,
+ int *major,
+ int *minor) = NULL;
+static Bool (*sym_DRI2Connect)(Display *display,
+ XID window,
+ char **driverName,
+ char **deviceName) = NULL;
+static Bool (*sym_DRI2Authenticate)(Display *display,
+ XID window,
+ drm_magic_t magic) = NULL;
+
+//// dri/drm data needed
+static int dri2_event = 0;
+static int dri2_error = 0;
+static int dri2_major = 0;
+static int dri2_minor = 0;
+static char *device_name = 0;
+static char *driver_name = 0;
+static drm_magic_t drm_magic;
+
+static int drm_fd = -1;
+static int drm_event_is_busy = 0;
+static int drm_animators_interval = 1;
+static drmEventContext drm_evctx;
+static Ecore_Fd_Handler *dri_drm_fdh = NULL;
+
+static void *dri_lib = NULL;
+static void *drm_lib = NULL;
+
+static Window dri_drm_vsync_root = 0;
+
+static void
+_dri_drm_tick_schedule(void)
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+ vbl.request.sequence = drm_animators_interval;
+ vbl.request.signal = 0;
+ sym_drmWaitVBlank(drm_fd, &vbl);
+}
+
+static void
+_dri_drm_tick_begin(void *data EINA_UNUSED)
+{
+ drm_event_is_busy = 1;
+ _dri_drm_tick_schedule();
+}
+
+static void
+_dri_drm_tick_end(void *data EINA_UNUSED)
+{
+ drm_event_is_busy = 0;
+}
+
+static void
+_dri_drm_vblank_handler(int fd EINA_UNUSED,
+ unsigned int frame EINA_UNUSED,
+ unsigned int sec EINA_UNUSED,
+ unsigned int usec EINA_UNUSED,
+ void *data EINA_UNUSED)
+{
+ ecore_animator_custom_tick();
+ if (drm_event_is_busy) _dri_drm_tick_schedule();
+}
+
+static Eina_Bool
+_dri_drm_cb(void *data EINA_UNUSED,
+ Ecore_Fd_Handler *fd_handler EINA_UNUSED)
+{
+ sym_drmHandleEvent(drm_fd, &drm_evctx);
+ return ECORE_CALLBACK_RENEW;
+}
+
+// yes. most evil. we dlopen libdrm and libGL etc. to manually find smbols
+// so we can be as compatible as possible given the whole mess of the
+// gl/dri/drm etc. world. and handle graceful failure at runtime not
+// compile time
+static int
+_dri_drm_link(void)
+{
+ const char *drm_libs[] =
+ {
+ "libdrm.so.2",
+ "libdrm.so.1",
+ "libdrm.so.0",
+ "libdrm.so",
+ NULL,
+ };
+ const char *dri_libs[] =
+ {
+ "libdri2.so.2",
+ "libdri2.so.1",
+ "libdri2.so.0",
+ "libdri2.so",
+ "libGL.so.4",
+ "libGL.so.3",
+ "libGL.so.2",
+ "libGL.so.1",
+ "libGL.so.0",
+ "libGL.so",
+ NULL,
+ };
+ int i, fail;
+#define SYM(lib, xx) \
+ do { \
+ sym_ ## xx = dlsym(lib, #xx); \
+ if (!(sym_ ## xx)) { \
+ fprintf(stderr, "%s\n", dlerror()); \
+ fail = 1; \
+ } \
+ } while (0)
+
+ if (dri_lib) return 1;
+ for (i = 0; drm_libs[i]; i++)
+ {
+ drm_lib = dlopen(drm_libs[i], RTLD_LOCAL | RTLD_LAZY);
+ if (drm_lib)
+ {
+ fail = 0;
+ SYM(drm_lib, drmClose);
+ SYM(drm_lib, drmWaitVBlank);
+ SYM(drm_lib, drmHandleEvent);
+ if (fail)
+ {
+ dlclose(drm_lib);
+ drm_lib = NULL;
+ }
+ else break;
+ }
+ }
+ if (!drm_lib) return 0;
+ for (i = 0; dri_libs[i]; i++)
+ {
+ dri_lib = dlopen(dri_libs[i], RTLD_LOCAL | RTLD_LAZY);
+ if (dri_lib)
+ {
+ fail = 0;
+ SYM(dri_lib, DRI2QueryExtension);
+ SYM(dri_lib, DRI2QueryVersion);
+ SYM(dri_lib, DRI2Connect);
+ SYM(dri_lib, DRI2Authenticate);
+ if (fail)
+ {
+ dlclose(dri_lib);
+ dri_lib = NULL;
+ }
+ else break;
+ }
+ }
+ if (!dri_lib)
+ {
+ dlclose(drm_lib);
+ drm_lib = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static int
+_dri_drm_init(void)
+{
+ if (!sym_DRI2QueryExtension(_ecore_x_disp, &dri2_event, &dri2_error))
+ return 0;
+ if (!sym_DRI2QueryVersion(_ecore_x_disp, &dri2_major, &dri2_minor))
+ return 0;
+ if (dri2_major < 2)
+ return 0;
+ if (!sym_DRI2Connect(_ecore_x_disp, dri_drm_vsync_root, &driver_name, &device_name))
+ return 0;
+ drm_fd = open(device_name, O_RDWR);
+ if (drm_fd < 0)
+ return 0;
+ sym_drmGetMagic(drm_fd, &drm_magic);
+ if (!sym_DRI2Authenticate(_ecore_x_disp, dri_drm_vsync_root, drm_magic))
+ {
+ close(drm_fd);
+ drm_fd = -1;
+ return 0;
+ }
+ memset(&drm_evctx, 0, sizeof(drm_evctx));
+ drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
+ drm_evctx.vblank_handler = _dri_drm_vblank_handler;
+ drm_evctx.page_flip_handler = NULL;
+
+ dri_drm_fdh = ecore_main_fd_handler_add(drm_fd, ECORE_FD_READ,
+ _dri_drm_cb, NULL, NULL, NULL);
+ if (!dri_drm_fdh)
+ {
+ close(drm_fd);
+ drm_fd = -1;
+ return 0;
+ }
+ return 1;
+}
+
+static void
+_dri_drm_shutdown(void)
+{
+ if (drm_fd >= 0)
+ {
+ close(drm_fd);
+ drm_fd = -1;
+ }
+ if (dri_drm_fdh)
+ {
+ ecore_main_fd_handler_del(dri_drm_fdh);
+ dri_drm_fdh = NULL;
+ }
+}
+
+#endif
+
+EAPI Eina_Bool
+ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win)
+{
+#ifdef ECORE_X_VSYNC_DRI2
+ Ecore_X_Window root;
+
+ root = ecore_x_window_root_get(win);
+ if (root != dri_drm_vsync_root)
+ {
+ dri_drm_vsync_root = root;
+ if (dri_drm_vsync_root)
+ {
+ if (!_dri_drm_link())
+ {
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ return EINA_FALSE;
+ }
+ _dri_drm_shutdown();
+ if (!_dri_drm_init())
+ {
+ dri_drm_vsync_root = 0;
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ return EINA_FALSE;
+ }
+ ecore_animator_custom_source_tick_begin_callback_set
+ (_dri_drm_tick_begin, NULL);
+ ecore_animator_custom_source_tick_end_callback_set
+ (_dri_drm_tick_end, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+ }
+ else
+ {
+ if (drm_fd >= 0)
+ {
+ _dri_drm_shutdown();
+ ecore_animator_custom_source_tick_begin_callback_set
+ (NULL, NULL);
+ ecore_animator_custom_source_tick_end_callback_set
+ (NULL, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ }
+ }
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ win = 0;
+#endif
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_window.c b/src/lib/ecore_x/xlib/ecore_x_window.c
new file mode 100644
index 0000000000..36fc5cc53a
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_window.c
@@ -0,0 +1,1727 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+static int ignore_num = 0;
+static Ecore_X_Window *ignore_list = NULL;
+
+/**
+ * @defgroup Ecore_X_Window_Create_Group X Window Creation Functions
+ *
+ * Functions that can be used to create an X window.
+ */
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Window win;
+ XSetWindowAttributes attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (parent == 0)
+ parent = DefaultRootWindow(_ecore_x_disp);
+
+ attr.backing_store = NotUseful;
+ attr.override_redirect = False;
+ attr.border_pixel = 0;
+ attr.background_pixmap = None;
+ attr.bit_gravity = NorthWestGravity;
+ attr.win_gravity = NorthWestGravity;
+ attr.save_under = False;
+ attr.do_not_propagate_mask = NoEventMask;
+ attr.event_mask = KeyPressMask |
+ KeyReleaseMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ EnterWindowMask |
+ LeaveWindowMask |
+ PointerMotionMask |
+ ExposureMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ FocusChangeMask |
+ PropertyChangeMask |
+ ColormapChangeMask;
+ win = XCreateWindow(_ecore_x_disp, parent,
+ x, y, w, h, 0,
+ CopyFromParent, /*DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/
+ InputOutput,
+ CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/
+ CWBackingStore |
+ CWOverrideRedirect |
+/* CWColormap | */
+ CWBorderPixel |
+ CWBackPixmap |
+ CWSaveUnder |
+ CWDontPropagate |
+ CWEventMask |
+ CWBitGravity |
+ CWWinGravity,
+ &attr);
+
+ if (parent == DefaultRootWindow(_ecore_x_disp))
+ ecore_x_window_defaults_set(win);
+
+ return win;
+}
+
+/**
+ * Creates a window with the override redirect attribute set to @c True.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_override_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Window win;
+ XSetWindowAttributes attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (parent == 0)
+ parent = DefaultRootWindow(_ecore_x_disp);
+
+ attr.backing_store = NotUseful;
+ attr.override_redirect = True;
+ attr.border_pixel = 0;
+ attr.background_pixmap = None;
+ attr.bit_gravity = NorthWestGravity;
+ attr.win_gravity = NorthWestGravity;
+ attr.save_under = False;
+ attr.do_not_propagate_mask = NoEventMask;
+ attr.event_mask = KeyPressMask |
+ KeyReleaseMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ EnterWindowMask |
+ LeaveWindowMask |
+ PointerMotionMask |
+ ExposureMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ FocusChangeMask |
+ PropertyChangeMask |
+ ColormapChangeMask;
+ win = XCreateWindow(_ecore_x_disp, parent,
+ x, y, w, h, 0,
+ CopyFromParent, /*DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/
+ InputOutput,
+ CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/
+ CWBackingStore |
+ CWOverrideRedirect |
+/* CWColormap | */
+ CWBorderPixel |
+ CWBackPixmap |
+ CWSaveUnder |
+ CWDontPropagate |
+ CWEventMask |
+ CWBitGravity |
+ CWWinGravity,
+ &attr);
+ return win;
+}
+
+/**
+ * Creates a new input window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_input_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ Window win;
+ XSetWindowAttributes attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (parent == 0)
+ parent = DefaultRootWindow(_ecore_x_disp);
+
+ attr.override_redirect = True;
+ attr.do_not_propagate_mask = NoEventMask;
+ attr.event_mask = KeyPressMask |
+ KeyReleaseMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ EnterWindowMask |
+ LeaveWindowMask |
+ PointerMotionMask |
+ ExposureMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ FocusChangeMask |
+ PropertyChangeMask |
+ ColormapChangeMask;
+ win = XCreateWindow(_ecore_x_disp, parent,
+ x, y, w, h, 0,
+ CopyFromParent,
+ InputOnly,
+ CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/
+ CWOverrideRedirect |
+ CWDontPropagate |
+ CWEventMask,
+ &attr);
+
+ if (parent == DefaultRootWindow(_ecore_x_disp))
+ {
+ }
+
+ return win;
+}
+
+/**
+ * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions
+ *
+ * Functions that set window properties.
+ */
+
+/**
+ * Sets the default properties for the given window.
+ *
+ * The default properties set for the window are @c WM_CLIENT_MACHINE and
+ * @c _NET_WM_PID.
+ *
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Properties_Group
+ */
+EAPI void
+ecore_x_window_defaults_set(Ecore_X_Window win)
+{
+ long pid;
+ char buf[MAXHOSTNAMELEN];
+ char *hostname[1];
+ int argc;
+ char **argv;
+ XTextProperty xprop;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /*
+ * Set WM_CLIENT_MACHINE.
+ */
+ gethostname(buf, MAXHOSTNAMELEN);
+ buf[MAXHOSTNAMELEN - 1] = '\0';
+ hostname[0] = buf;
+ /* The ecore function uses UTF8 which Xlib may not like (especially
+ * with older clients) */
+ /* ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_CLIENT_MACHINE,
+ (char *)buf); */
+ if (XStringListToTextProperty(hostname, 1, &xprop))
+ {
+ XSetWMClientMachine(_ecore_x_disp, win, &xprop);
+ XFree(xprop.value);
+ }
+
+ /*
+ * Set _NET_WM_PID
+ */
+ pid = getpid();
+ ecore_x_netwm_pid_set(win, pid);
+
+ ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL);
+
+ ecore_app_args_get(&argc, &argv);
+ ecore_x_icccm_command_set(win, argc, argv);
+}
+
+EAPI void
+ecore_x_window_configure(Ecore_X_Window win,
+ Ecore_X_Window_Configure_Mask mask,
+ int x,
+ int y,
+ int w,
+ int h,
+ int border_width,
+ Ecore_X_Window sibling,
+ int stack_mode)
+{
+ XWindowChanges xwc;
+
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+ xwc.x = x;
+ xwc.y = y;
+ xwc.width = w;
+ xwc.height = h;
+ xwc.border_width = border_width;
+ xwc.sibling = sibling;
+ xwc.stack_mode = stack_mode;
+
+ XConfigureWindow(_ecore_x_disp, win, mask, &xwc);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Destroy_Group X Window Destroy Functions
+ *
+ * Functions to destroy X windows.
+ */
+
+/**
+ * Deletes the given window.
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Destroy_Group
+ */
+EAPI void
+ecore_x_window_free(Ecore_X_Window win)
+{
+ /* sorry sir, deleting the root window doesn't sound like
+ * a smart idea.
+ */
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win)
+ XDestroyWindow(_ecore_x_disp, win);
+}
+
+/**
+ * Set if a window should be ignored.
+ * @param win The given window.
+ * @param ignore if to ignore
+ */
+EAPI void
+ecore_x_window_ignore_set(Ecore_X_Window win,
+ int ignore)
+{
+ int i, j, cnt;
+ Ecore_X_Window *t;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (ignore)
+ {
+ if (ignore_list)
+ {
+ for (i = 0; i < ignore_num; i++)
+ {
+ if (win == ignore_list[i])
+ return;
+ }
+ t = realloc(ignore_list, (ignore_num + 1) * sizeof(Ecore_X_Window));
+ if (!t) return;
+ ignore_list = t;
+ ignore_list[ignore_num++] = win;
+ }
+ else
+ {
+ ignore_num = 0;
+ ignore_list = malloc(sizeof(Ecore_X_Window));
+ if (ignore_list)
+ ignore_list[ignore_num++] = win;
+ }
+ }
+ else
+ {
+ if (!ignore_list)
+ return;
+
+ for (cnt = ignore_num, i = 0, j = 0; i < cnt; i++)
+ {
+ if (win != ignore_list[i])
+ ignore_list[j++] = ignore_list[i];
+ else
+ ignore_num--;
+ }
+
+ if (ignore_num <= 0)
+ {
+ free(ignore_list);
+ ignore_list = NULL;
+ return;
+ }
+ t = realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window));
+ if (t) ignore_list = t;
+ }
+}
+
+/**
+ * Get the ignore list
+ * @param num number of windows in the list
+ * @return list of windows to ignore
+ */
+EAPI Ecore_X_Window *
+ecore_x_window_ignore_list(int *num)
+{
+ if (num)
+ *num = ignore_num;
+
+ return ignore_list;
+}
+
+/**
+ * Sends a delete request to the given window.
+ * @param win The given window.
+ * @ingroup Ecore_X_Window_Destroy_Group
+ */
+EAPI void
+ecore_x_window_delete_request_send(Ecore_X_Window win)
+{
+ XEvent xev;
+
+ /* sorry sir, deleting the root window doesn't sound like
+ * a smart idea.
+ */
+ if (!win)
+ return;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = _ecore_x_disp;
+ xev.xclient.window = win;
+ xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = ECORE_X_ATOM_WM_DELETE_WINDOW;
+ xev.xclient.data.l[1] = CurrentTime;
+
+ XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions
+ *
+ * Functions to access and change the visibility of X windows.
+ */
+
+/**
+ * Shows a window.
+ *
+ * Synonymous to "mapping" a window in X Window System terminology.
+ *
+ * @param win The window to show.
+ * @ingroup Ecore_X_Window_Visibility
+ */
+EAPI void
+ecore_x_window_show(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XMapWindow(_ecore_x_disp, win);
+}
+
+/**
+ * Hides a window.
+ *
+ * Synonymous to "unmapping" a window in X Window System terminology.
+ *
+ * @param win The window to hide.
+ * @ingroup Ecore_X_Window_Visibility
+ */
+EAPI void
+ecore_x_window_hide(Ecore_X_Window win)
+{
+ XEvent xev;
+ Window root;
+ int idum;
+ unsigned int uidum;
+
+ /* ICCCM: SEND unmap event... */
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ root = win;
+ if (ScreenCount(_ecore_x_disp) == 1)
+ root = DefaultRootWindow(_ecore_x_disp);
+ else
+ XGetGeometry(_ecore_x_disp,
+ win,
+ &root,
+ &idum,
+ &idum,
+ &uidum,
+ &uidum,
+ &uidum,
+ &uidum);
+
+ XUnmapWindow(_ecore_x_disp, win);
+ xev.xunmap.type = UnmapNotify;
+ xev.xunmap.serial = 0;
+ xev.xunmap.send_event = True;
+ xev.xunmap.display = _ecore_x_disp;
+ xev.xunmap.event = root;
+ xev.xunmap.window = win;
+ xev.xunmap.from_configure = False;
+ XSendEvent(_ecore_x_disp, xev.xunmap.event, False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Geometry_Group X Window Geometry Functions
+ *
+ * Functions that change or retrieve the geometry of X windows.
+ */
+
+/**
+ * Moves a window to the position @p x, @p y.
+ *
+ * The position is relative to the upper left hand corner of the
+ * parent window.
+ *
+ * @param win The window to move.
+ * @param x X position.
+ * @param y Y position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_move(Ecore_X_Window win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XMoveWindow(_ecore_x_disp, win, x, y);
+}
+
+/**
+ * Resizes a window.
+ * @param win The window to resize.
+ * @param w New width of the window.
+ * @param h New height of the window.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_resize(Ecore_X_Window win,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (w < 1)
+ w = 1;
+
+ if (h < 1)
+ h = 1;
+
+ XResizeWindow(_ecore_x_disp, win, w, h);
+}
+
+/**
+ * Moves and resizes a window.
+ * @param win The window to move and resize.
+ * @param x New X position of the window.
+ * @param y New Y position of the window.
+ * @param w New width of the window.
+ * @param h New height of the window.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_move_resize(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (w < 1)
+ w = 1;
+
+ if (h < 1)
+ h = 1;
+
+ XMoveResizeWindow(_ecore_x_disp, win, x, y, w, h);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Focus_Functions X Window Focus Functions
+ *
+ * Functions that give the focus to an X Window.
+ */
+
+/**
+ * Sets the focus to the window @p win.
+ * @param win The window to focus.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI void
+ecore_x_window_focus(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp); // XSetInputFocus(_ecore_x_disp, win, RevertToNone, CurrentTime);
+
+// XSetInputFocus(_ecore_x_disp, win, RevertToPointerRoot, CurrentTime);
+ XSetInputFocus(_ecore_x_disp, win, RevertToParent, CurrentTime);
+}
+
+/**
+ * Sets the focus to the given window at a specific time.
+ * @param win The window to focus.
+ * @param t When to set the focus to the window.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI void
+ecore_x_window_focus_at_time(Ecore_X_Window win,
+ Ecore_X_Time t)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp); // XSetInputFocus(_ecore_x_disp, win, RevertToNone, t);
+
+// XSetInputFocus(_ecore_x_disp, win, PointerRoot, t);
+ XSetInputFocus(_ecore_x_disp, win, RevertToParent, t);
+}
+
+/**
+ * gets the window that has focus.
+ * @return The window that has focus.
+ * @ingroup Ecore_X_Window_Focus_Functions
+ */
+EAPI Ecore_X_Window
+ecore_x_window_focus_get(void)
+{
+ Window win;
+ int revert_mode;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ win = 0;
+ XGetInputFocus(_ecore_x_disp, &win, &revert_mode);
+ return win;
+}
+
+/**
+ * @defgroup Ecore_X_Window_Z_Order_Group X Window Z Order Functions
+ *
+ * Functions that change the Z order of X windows.
+ */
+
+/**
+ * Raises the given window.
+ * @param win The window to raise.
+ * @ingroup Ecore_X_Window_Z_Order_Group
+ */
+EAPI void
+ecore_x_window_raise(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XRaiseWindow(_ecore_x_disp, win);
+}
+
+/**
+ * Lowers the given window.
+ * @param win The window to lower.
+ * @ingroup Ecore_X_Window_Z_Order_Group
+ */
+EAPI void
+ecore_x_window_lower(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XLowerWindow(_ecore_x_disp, win);
+}
+
+/**
+ * @defgroup Ecore_X_Window_Parent_Group X Window Parent Functions
+ *
+ * Functions that retrieve or changes the parent window of a window.
+ */
+
+/**
+ * Moves a window to within another window at a given position.
+ * @param win The window to reparent.
+ * @param new_parent The new parent window.
+ * @param x X position within new parent window.
+ * @param y Y position within new parent window.
+ * @ingroup Ecore_X_Window_Parent_Group
+ */
+EAPI void
+ecore_x_window_reparent(Ecore_X_Window win,
+ Ecore_X_Window new_parent,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (new_parent == 0)
+ new_parent = DefaultRootWindow(_ecore_x_disp);
+
+ XReparentWindow(_ecore_x_disp, win, new_parent, x, y);
+}
+
+/**
+ * Retrieves the size of the given window.
+ * @param win The given window.
+ * @param w Pointer to an integer into which the width is to be stored.
+ * @param h Pointer to an integer into which the height is to be stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_size_get(Ecore_X_Window win,
+ int *w,
+ int *h)
+{
+ int dummy_x, dummy_y;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ ecore_x_drawable_geometry_get(win, &dummy_x, &dummy_y, w, h);
+}
+
+/**
+ * Retrieves the geometry of the given window.
+ *
+ * Note that the x & y coordinates are relative to your parent. In
+ * particular for reparenting window managers - relative to you window border.
+ * If you want screen coordinates either walk the window tree to the root,
+ * else for ecore_evas applications see ecore_evas_geometry_get(). Elementary
+ * applications can use elm_win_screen_position_get().
+ *
+ * @param win The given window.
+ * @param x Pointer to an integer in which the X position is to be stored.
+ * @param y Pointer to an integer in which the Y position is to be stored.
+ * @param w Pointer to an integer in which the width is to be stored.
+ * @param h Pointer to an integer in which the height is to be stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_geometry_get(Ecore_X_Window win,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ ecore_x_drawable_geometry_get(win, x, y, w, h);
+}
+
+/**
+ * Retrieves the width of the border of the given window.
+ * @param win The given window.
+ * @return Width of the border of @p win.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI int
+ecore_x_window_border_width_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* doesn't make sense to call this on a root window */
+ if (!win)
+ return 0;
+
+ return ecore_x_drawable_border_width_get(win);
+}
+
+/**
+ * Sets the width of the border of the given window.
+ * @param win The given window.
+ * @param width The new border width.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_border_width_set(Ecore_X_Window win,
+ int width)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* doesn't make sense to call this on a root window */
+ if (!win)
+ return;
+
+ XSetWindowBorderWidth (_ecore_x_disp, win, width);
+}
+
+/**
+ * Retrieves the depth of the given window.
+ * @param win The given window.
+ * @return Depth of the window.
+ */
+EAPI int
+ecore_x_window_depth_get(Ecore_X_Window win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_drawable_depth_get(win);
+}
+
+/**
+ * @brief Show the cursor on a window of type Ecore_X_Window.
+ * @param win The window for which the cursor will be showed.
+ * @param show Enables the show of the cursor on the window if equals EINA_TRUE, disables if equals EINA_FALSE.
+ */
+EAPI void
+ecore_x_window_cursor_show(Ecore_X_Window win,
+ Eina_Bool show)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ if (!show)
+ {
+ Cursor c;
+ XColor cl;
+ Pixmap p, m;
+ GC gc;
+ XGCValues gcv;
+
+ p = XCreatePixmap(_ecore_x_disp, win, 1, 1, 1);
+ m = XCreatePixmap(_ecore_x_disp, win, 1, 1, 1);
+ gc = XCreateGC(_ecore_x_disp, m, 0, &gcv);
+ XSetForeground(_ecore_x_disp, gc, 0);
+ XDrawPoint(_ecore_x_disp, m, gc, 0, 0);
+ XFreeGC(_ecore_x_disp, gc);
+ c = XCreatePixmapCursor(_ecore_x_disp, p, m, &cl, &cl, 0, 0);
+ XDefineCursor(_ecore_x_disp, win, c);
+ XFreeCursor(_ecore_x_disp, c);
+ XFreePixmap(_ecore_x_disp, p);
+ XFreePixmap(_ecore_x_disp, m);
+ }
+ else
+ XDefineCursor(_ecore_x_disp, win, 0);
+}
+
+EAPI void
+ecore_x_window_cursor_set(Ecore_X_Window win,
+ Ecore_X_Cursor c)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (c == 0)
+ XUndefineCursor(_ecore_x_disp, win);
+ else
+ XDefineCursor(_ecore_x_disp, win, c);
+}
+
+/**
+ * Finds out whether the given window is currently visible.
+ * @param win The given window.
+ * @return 1 if the window is visible, otherwise 0.
+ * @ingroup Ecore_X_Window_Visibility_Group
+ */
+EAPI int
+ecore_x_window_visible_get(Ecore_X_Window win)
+{
+ XWindowAttributes attr;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return XGetWindowAttributes(_ecore_x_disp, win, &attr) &&
+ (attr.map_state == IsViewable);
+}
+
+typedef struct _Shadow Shadow;
+struct _Shadow
+{
+ Shadow *parent;
+ Shadow **children;
+ Window win;
+ int children_num;
+ short x, y;
+ unsigned short w, h;
+};
+
+static Shadow **shadow_base = NULL;
+static int shadow_num = 0;
+
+static Shadow *
+_ecore_x_window_tree_walk(Window win)
+{
+ Window *list = NULL;
+ Window parent_win = 0, root_win = 0;
+ unsigned int num;
+ Shadow *s, **sl;
+ XWindowAttributes att;
+
+ if (!XGetWindowAttributes(_ecore_x_disp, win, &att))
+ return NULL; // if (att.class == InputOnly) return NULL;
+
+ if (att.map_state != IsViewable)
+ return NULL;
+
+ s = calloc(1, sizeof(Shadow));
+ if (!s)
+ return NULL;
+
+ s->win = win;
+ s->x = att.x;
+ s->y = att.y;
+ s->w = att.width;
+ s->h = att.height;
+ if (XQueryTree(_ecore_x_disp, s->win, &root_win, &parent_win,
+ &list, &num))
+ {
+ s->children = calloc(1, sizeof(Shadow *) * num);
+ if (s->children)
+ {
+ size_t i, j;
+ s->children_num = num;
+ for (i = 0; i < num; i++)
+ {
+ s->children[i] = _ecore_x_window_tree_walk(list[i]);
+ if (s->children[i])
+ s->children[i]->parent = s;
+ }
+ /* compress list down */
+ j = 0;
+ for (i = 0; i < num; i++)
+ {
+ if (s->children[i])
+ {
+ s->children[j] = s->children[i];
+ j++;
+ }
+ }
+ if (j == 0)
+ {
+ free(s->children);
+ s->children = NULL;
+ s->children_num = 0;
+ }
+ else
+ {
+ s->children_num = j;
+ sl = realloc(s->children, sizeof(Shadow *) * j);
+ if (sl)
+ s->children = sl;
+ }
+ }
+ }
+
+ if (list)
+ XFree(list);
+
+ return s;
+}
+
+static void
+_ecore_x_window_tree_shadow_free1(Shadow *s)
+{
+ int i;
+
+ if (!s)
+ return;
+
+ if (s->children)
+ {
+ for (i = 0; i < s->children_num; i++)
+ {
+ if (s->children[i])
+ _ecore_x_window_tree_shadow_free1(s->children[i]);
+ }
+ free(s->children);
+ }
+
+ free(s);
+}
+
+static void
+_ecore_x_window_tree_shadow_free(void)
+{
+ int i;
+
+ if (!shadow_base)
+ return;
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i])
+ continue;
+
+ _ecore_x_window_tree_shadow_free1(shadow_base[i]);
+ }
+ free(shadow_base);
+ shadow_base = NULL;
+ shadow_num = 0;
+}
+
+static void
+_ecore_x_window_tree_shadow_populate(void)
+{
+ Ecore_X_Window *roots;
+ int i, num;
+
+ roots = ecore_x_window_root_list(&num);
+ if (roots)
+ {
+ shadow_base = calloc(1, sizeof(Shadow *) * num);
+ if (shadow_base)
+ {
+ shadow_num = num;
+ for (i = 0; i < num; i++)
+ shadow_base[i] = _ecore_x_window_tree_walk(roots[i]);
+ }
+
+ free(roots);
+ }
+}
+
+/*
+ static int shadow_count = 0;
+
+ static void
+ _ecore_x_window_tree_shadow_start(void)
+ {
+ shadow_count++;
+ if (shadow_count > 1) return;
+ _ecore_x_window_tree_shadow_populate();
+ }
+
+ static void
+ _ecore_x_window_tree_shadow_stop(void)
+ {
+ shadow_count--;
+ if (shadow_count != 0) return;
+ _ecore_x_window_tree_shadow_free();
+ }
+ */
+
+static Shadow *
+_ecore_x_window_shadow_tree_find_shadow(Shadow *s,
+ Window win)
+{
+ Shadow *ss;
+ int i;
+
+ if (s->win == win)
+ return s;
+
+ if (s->children)
+ for (i = 0; i < s->children_num; i++)
+ {
+ if (!s->children[i])
+ continue;
+
+ if ((ss =
+ _ecore_x_window_shadow_tree_find_shadow(s->children[i], win)))
+ return ss;
+ }
+
+ return NULL;
+}
+
+static Shadow *
+_ecore_x_window_shadow_tree_find(Window base)
+{
+ Shadow *s;
+ int i;
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i])
+ continue;
+
+ if ((s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], base)))
+ return s;
+ }
+ return NULL;
+}
+
+static int
+_inside_rects(Shadow *s,
+ int x,
+ int y,
+ int bx,
+ int by,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+ int i, inside;
+
+ if (!rects) return 0;
+ inside = 0;
+ for (i = 0; i < num; i++)
+ {
+ if ((x >= s->x + bx + rects[i].x) &&
+ (y >= s->y + by + rects[i].y) &&
+ (x < (int)(s->x + bx + rects[i].x + rects[i].width)) &&
+ (y < (int)(s->y + by + rects[i].y + rects[i].height)))
+ {
+ inside = 1;
+ break;
+ }
+ }
+ free(rects);
+ return inside;
+}
+
+static Window
+_ecore_x_window_shadow_tree_at_xy_get_shadow(Shadow *s,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Window child;
+ int i, j;
+ int wx, wy;
+
+ wx = s->x + bx;
+ wy = s->y + by;
+ if (!((x >= wx) && (y >= wy) && (x < (wx + s->w)) && (y < (wy + s->h))))
+ return 0;
+
+ /* FIXME: get shape */
+ {
+ int num;
+ Ecore_X_Rectangle *rects;
+
+ num = 0;
+ rects = ecore_x_window_shape_rectangles_get(s->win, &num);
+ if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
+ num = 0;
+ rects = ecore_x_window_shape_input_rectangles_get(s->win, &num);
+ if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
+ }
+
+ if (s->children)
+ {
+ int skipit = 0;
+
+ for (i = s->children_num - 1; i >= 0; --i)
+ {
+ if (!s->children[i])
+ continue;
+
+ skipit = 0;
+ if (skip)
+ for (j = 0; j < skip_num; j++)
+ {
+ if (s->children[i]->win == skip[j])
+ {
+ skipit = 1;
+ goto onward;
+ }
+ }
+
+onward:
+ if (!skipit)
+ if ((child =
+ _ecore_x_window_shadow_tree_at_xy_get_shadow(s->
+ children[i
+ ], wx, wy,
+ x, y, skip,
+ skip_num)))
+ return child;
+ }
+ }
+
+ return s->win;
+}
+
+static Window
+_ecore_x_window_shadow_tree_at_xy_get(Window base,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Shadow *s;
+
+ if (!shadow_base)
+ {
+ _ecore_x_window_tree_shadow_populate();
+ if (!shadow_base)
+ return 0;
+ }
+
+ s = _ecore_x_window_shadow_tree_find(base);
+ if (!s)
+ return 0;
+
+ return _ecore_x_window_shadow_tree_at_xy_get_shadow(s,
+ bx,
+ by,
+ x,
+ y,
+ skip,
+ skip_num);
+}
+
+/**
+ * Retrieves the top, visible window at the given location,
+ * but skips the windows in the list. This uses a shadow tree built from the
+ * window tree that is only updated the first time
+ * ecore_x_window_shadow_tree_at_xy_with_skip_get() is called, or the next time
+ * it is called after a ecore_x_window_shadow_tree_flush()
+ * @param base The base window to start searching from (normally root).
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @param skip The list of windows to be skipped.
+ * @param skip_num The number of windows to be skipped.
+ * @return The window at that position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_window_shadow_tree_at_xy_get(base,
+ 0,
+ 0,
+ x,
+ y,
+ skip,
+ skip_num);
+}
+
+/**
+ * Retrieves the parent window a given window has. This uses the shadow window
+ * tree.
+ * @param root The root window of @p win - if 0, this will be automatically determined with extra processing overhead
+ * @param win The window to get the parent window of
+ * @return The parent window of @p win
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_shadow_parent_get(Ecore_X_Window root EINA_UNUSED,
+ Ecore_X_Window win)
+{
+ Shadow *s;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!shadow_base)
+ {
+ _ecore_x_window_tree_shadow_populate();
+ if (!shadow_base)
+ return 0;
+ }
+
+ for (i = 0; i < shadow_num; i++)
+ {
+ if (!shadow_base[i])
+ continue;
+
+ s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win);
+ if (s)
+ {
+ if (!s->parent)
+ return 0;
+
+ return s->parent->win;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Flushes the window shadow tree so nothing is stored.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI void
+ecore_x_window_shadow_tree_flush(void)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ _ecore_x_window_tree_shadow_free();
+}
+
+/**
+ * Retrieves the root window a given window is on.
+ * @param win The window to get the root window of
+ * @return The root window of @p win
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_root_get(Ecore_X_Window win)
+{
+ XWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetWindowAttributes(_ecore_x_disp, win, &att))
+ return 0;
+
+ return att.root;
+}
+
+static Window
+_ecore_x_window_at_xy_get(Window base,
+ int bx,
+ int by,
+ int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Window *list = NULL;
+ Window parent_win = 0, child = 0, root_win = 0;
+ int i, j, wx, wy, ww, wh;
+ unsigned int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!ecore_x_window_visible_get(base))
+ return 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_geometry_get(base, &wx, &wy, &ww, &wh);
+ wx += bx;
+ wy += by;
+
+ if (!((x >= wx) && (y >= wy) && (x < (wx + ww)) && (y < (wy + wh))))
+ return 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XQueryTree(_ecore_x_disp, base, &root_win, &parent_win, &list, &num))
+ return base;
+
+ if (list)
+ {
+ int skipit = 0;
+
+ for (i = num - 1; i >= 0; --i)
+ {
+ skipit = 0;
+
+ if (skip)
+ for (j = 0; j < skip_num; j++)
+ {
+ if (list[i] == skip[j])
+ {
+ skipit = 1;
+ goto onward;
+ }
+ }
+
+onward:
+ if (!skipit)
+ if ((child =
+ _ecore_x_window_at_xy_get(list[i], wx, wy, x, y, skip,
+ skip_num)))
+ {
+ XFree(list);
+ return child;
+ }
+ }
+ XFree(list);
+ }
+
+ return base;
+}
+
+/**
+ * Retrieves the top, visible window at the given location.
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @return The window at that position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_get(int x,
+ int y)
+{
+ Ecore_X_Window win, root;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* FIXME: Proper function to determine current root/virtual root
+ * window missing here */
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ ecore_x_grab();
+ win = _ecore_x_window_at_xy_get(root, 0, 0, x, y, NULL, 0);
+ ecore_x_ungrab();
+
+ return win ? win : root;
+}
+
+/**
+ * Retrieves the top, visible window at the given location,
+ * but skips the windows in the list.
+ * @param x The given X position.
+ * @param y The given Y position.
+ * @param skip The list of windows to be skipped.
+ * @param skip_num The number of windows to be skipped.
+ * @return The window at that position.
+ * @ingroup Ecore_X_Window_Geometry_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_with_skip_get(int x,
+ int y,
+ Ecore_X_Window *skip,
+ int skip_num)
+{
+ Ecore_X_Window win, root;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ /* FIXME: Proper function to determine current root/virtual root
+ * window missing here */
+ root = DefaultRootWindow(_ecore_x_disp);
+
+ ecore_x_grab();
+ win = _ecore_x_window_at_xy_get(root, 0, 0, x, y, skip, skip_num);
+ ecore_x_ungrab();
+
+ return win ? win : root;
+}
+
+EAPI Ecore_X_Window
+ecore_x_window_at_xy_begin_get(Ecore_X_Window begin,
+ int x,
+ int y)
+{
+ Ecore_X_Window win;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_grab();
+ win = _ecore_x_window_at_xy_get(begin, 0, 0, x, y, NULL, 0);
+ ecore_x_ungrab();
+
+ return win ? win : begin;
+}
+
+/**
+ * Retrieves the parent window of the given window.
+ * @param win The given window.
+ * @return The parent window of @p win.
+ * @ingroup Ecore_X_Window_Parent_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_parent_get(Ecore_X_Window win)
+{
+ Window root, parent, *children = NULL;
+ unsigned int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XQueryTree(_ecore_x_disp, win, &root, &parent, &children, &num))
+ return 0;
+
+ if (children)
+ XFree(children);
+
+ return parent;
+}
+
+/**
+ * Sets the background color of the given window.
+ * @param win The given window
+ * @param r red value (0...65536, 16 bits)
+ * @param g green value (0...65536, 16 bits)
+ * @param b blue value (0...65536, 16 bits)
+ */
+EAPI void
+ecore_x_window_background_color_set(Ecore_X_Window win,
+ unsigned short r,
+ unsigned short g,
+ unsigned short b)
+{
+ XSetWindowAttributes attr;
+ Colormap map;
+ XColor col;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ col.red = r;
+ col.green = g;
+ col.blue = b;
+
+ map = DefaultColormap(_ecore_x_disp, DefaultScreen(_ecore_x_disp));
+ XAllocColor(_ecore_x_disp, map, &col);
+
+ attr.background_pixel = col.pixel;
+ XChangeWindowAttributes(_ecore_x_disp, win, CWBackPixel, &attr);
+}
+
+EAPI void
+ecore_x_window_gravity_set(Ecore_X_Window win,
+ Ecore_X_Gravity grav)
+{
+ XSetWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ att.win_gravity = grav;
+ XChangeWindowAttributes(_ecore_x_disp, win, CWWinGravity, &att);
+}
+
+EAPI void
+ecore_x_window_pixel_gravity_set(Ecore_X_Window win,
+ Ecore_X_Gravity grav)
+{
+ XSetWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ att.bit_gravity = grav;
+ XChangeWindowAttributes(_ecore_x_disp, win, CWBitGravity, &att);
+}
+
+EAPI void
+ecore_x_window_pixmap_set(Ecore_X_Window win,
+ Ecore_X_Pixmap pmap)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XSetWindowBackgroundPixmap(_ecore_x_disp, win, pmap);
+}
+
+EAPI void
+ecore_x_window_area_clear(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XClearArea(_ecore_x_disp, win, x, y, w, h, False);
+}
+
+EAPI void
+ecore_x_window_area_expose(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XClearArea(_ecore_x_disp, win, x, y, w, h, True);
+}
+
+EAPI void
+ecore_x_window_override_set(Ecore_X_Window win,
+ Eina_Bool override)
+{
+ XSetWindowAttributes att;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ att.override_redirect = override;
+ XChangeWindowAttributes(_ecore_x_disp, win, CWOverrideRedirect, &att);
+}
+
+#ifdef ECORE_XRENDER
+static Ecore_X_Window
+_ecore_x_window_argb_internal_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h,
+ Eina_Bool override,
+ Eina_Bool saveunder)
+{
+ Window win;
+ XSetWindowAttributes attr;
+ XWindowAttributes att;
+ XVisualInfo *xvi;
+ XVisualInfo vi_in;
+ int nvi, i, scr = 0;
+ XRenderPictFormat *fmt;
+ Visual *vis;
+
+ if (parent == 0)
+ {
+ parent = DefaultRootWindow(_ecore_x_disp);
+ scr = DefaultScreen(_ecore_x_disp);
+ }
+ else
+ {
+ /* ewww - round trip */
+ XGetWindowAttributes(_ecore_x_disp, parent, &att);
+ for (i = 0; i < ScreenCount(_ecore_x_disp); i++)
+ {
+ if (att.screen == ScreenOfDisplay(_ecore_x_disp, i))
+ {
+ scr = i;
+ break;
+ }
+ }
+ }
+
+ vi_in.screen = scr;
+ vi_in.depth = 32;
+ vi_in.class = TrueColor;
+ xvi = XGetVisualInfo(_ecore_x_disp,
+ VisualScreenMask |
+ VisualDepthMask |
+ VisualClassMask,
+ &vi_in,
+ &nvi);
+ if (!xvi)
+ return 0;
+
+ vis = NULL;
+ for (i = 0; i < nvi; i++)
+ {
+ fmt = XRenderFindVisualFormat(_ecore_x_disp, xvi[i].visual);
+ if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask))
+ {
+ vis = xvi[i].visual;
+ break;
+ }
+ }
+ XFree (xvi);
+
+ attr.backing_store = NotUseful;
+ attr.override_redirect = override;
+ attr.colormap = XCreateColormap(_ecore_x_disp, parent,
+ vis, AllocNone);
+ attr.border_pixel = 0;
+ attr.background_pixmap = None;
+ attr.bit_gravity = NorthWestGravity;
+ attr.win_gravity = NorthWestGravity;
+ attr.save_under = saveunder;
+ attr.do_not_propagate_mask = NoEventMask;
+ attr.event_mask = KeyPressMask |
+ KeyReleaseMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ EnterWindowMask |
+ LeaveWindowMask |
+ PointerMotionMask |
+ ExposureMask |
+ VisibilityChangeMask |
+ StructureNotifyMask |
+ FocusChangeMask |
+ PropertyChangeMask |
+ ColormapChangeMask;
+ win = XCreateWindow(_ecore_x_disp, parent,
+ x, y, w, h, 0,
+ 32,
+ InputOutput,
+ vis,
+ CWBackingStore |
+ CWOverrideRedirect |
+ CWColormap |
+ CWBorderPixel |
+ CWBackPixmap |
+ CWSaveUnder |
+ CWDontPropagate |
+ CWEventMask |
+ CWBitGravity |
+ CWWinGravity,
+ &attr);
+ XFreeColormap(_ecore_x_disp, attr.colormap);
+
+ if (parent == DefaultRootWindow(_ecore_x_disp))
+ ecore_x_window_defaults_set(win);
+
+ return win;
+}
+
+#endif /* ifdef ECORE_XRENDER */
+
+EAPI int
+ecore_x_window_argb_get(Ecore_X_Window win)
+{
+#ifdef ECORE_XRENDER
+ XWindowAttributes att;
+ XRenderPictFormat *fmt;
+
+ att.visual = 0;
+ if (!XGetWindowAttributes(_ecore_x_disp, win, &att))
+ return 0;
+
+ fmt = XRenderFindVisualFormat(_ecore_x_disp, att.visual);
+ if (!fmt)
+ return 0;
+
+ if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask))
+ return 1;
+
+ return 0;
+#else /* ifdef ECORE_XRENDER */
+ return 0;
+#endif /* ifdef ECORE_XRENDER */
+}
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_manager_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XRENDER
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0);
+#else /* ifdef ECORE_XRENDER */
+ return 0;
+#endif /* ifdef ECORE_XRENDER */
+}
+
+/**
+ * Creates a new window.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XRENDER
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 0, 0);
+#else /* ifdef ECORE_XRENDER */
+ return 0;
+#endif /* ifdef ECORE_XRENDER */
+}
+
+/**
+ * Creates a window with the override redirect attribute set to @c True.
+ * @param parent The parent window to use. If @p parent is @c 0, the root
+ * window of the default display is used.
+ * @param x X position.
+ * @param y Y position.
+ * @param w Width.
+ * @param h Height.
+ * @return The new window handle.
+ * @ingroup Ecore_X_Window_Create_Group
+ */
+EAPI Ecore_X_Window
+ecore_x_window_override_argb_new(Ecore_X_Window parent,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ECORE_XRENDER
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0);
+#else /* ifdef ECORE_XRENDER */
+ return 0;
+#endif /* ifdef ECORE_XRENDER */
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_window_prop.c b/src/lib/ecore_x/xlib/ecore_x_window_prop.c
new file mode 100644
index 0000000000..535c521941
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_window_prop.c
@@ -0,0 +1,760 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+#include <inttypes.h>
+#include <limits.h>
+
+#define _ATOM_SET_CARD32(win, atom, p_val, cnt) \
+ XChangeProperty(_ecore_x_disp, win, atom, XA_CARDINAL, 32, PropModeReplace, \
+ (unsigned char *)p_val, cnt)
+
+/*
+ * Set CARD32 (array) property
+ */
+EAPI void
+ecore_x_window_prop_card32_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int *val,
+ unsigned int num)
+{
+#if SIZEOF_INT == SIZEOF_LONG
+ _ATOM_SET_CARD32(win, atom, val, num);
+#else /* if SIZEOF_INT == SIZEOF_LONG */
+ long *v2;
+ unsigned int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ v2 = malloc(num * sizeof(long));
+ if (!v2)
+ return;
+
+ for (i = 0; i < num; i++)
+ v2[i] = val[i];
+ _ATOM_SET_CARD32(win, atom, v2, num);
+ free(v2);
+#endif /* if SIZEOF_INT == SIZEOF_LONG */
+}
+
+/*
+ * Get CARD32 (array) property
+ *
+ * At most len items are returned in val.
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_card32_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int *val,
+ unsigned int len)
+{
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ unsigned int i;
+ int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ prop_ret = NULL;
+ if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ XA_CARDINAL, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ return -1;
+
+ if (type_ret != XA_CARDINAL || format_ret != 32)
+ num = -1;
+ else if (num_ret == 0 || !prop_ret)
+ num = 0;
+ else
+ {
+ if (num_ret < len)
+ len = num_ret;
+
+ for (i = 0; i < len; i++)
+ val[i] = ((unsigned long *)prop_ret)[i];
+ num = len;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return num;
+}
+
+/*
+ * Get CARD32 (array) property of any length
+ *
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_card32_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ unsigned int **plst)
+{
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ unsigned int i, *val;
+ int num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ *plst = NULL;
+ prop_ret = NULL;
+ if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ XA_CARDINAL, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ return -1;
+
+ if ((type_ret != XA_CARDINAL) || (format_ret != 32))
+ num = -1;
+ else if ((num_ret == 0) || (!prop_ret))
+ num = 0;
+ else
+ {
+ val = malloc(num_ret * sizeof(unsigned int));
+ if (!val)
+ {
+ if (prop_ret) XFree(prop_ret);
+ return -1;
+ }
+ for (i = 0; i < num_ret; i++)
+ val[i] = ((unsigned long *)prop_ret)[i];
+ num = num_ret;
+ *plst = val;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return num;
+}
+
+/*
+ * Set X ID (array) property
+ */
+EAPI void
+ecore_x_window_prop_xid_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID *lst,
+ unsigned int num)
+{
+#if SIZEOF_INT == SIZEOF_LONG
+ XChangeProperty(_ecore_x_disp, win, atom, type, 32, PropModeReplace,
+ (unsigned char *)lst, num);
+#else /* if SIZEOF_INT == SIZEOF_LONG */
+ unsigned long *pl;
+ unsigned int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ pl = malloc(num * sizeof(long));
+ if (!pl)
+ return;
+
+ for (i = 0; i < num; i++)
+ pl[i] = lst[i];
+ XChangeProperty(_ecore_x_disp, win, atom, type, 32, PropModeReplace,
+ (unsigned char *)pl, num);
+ free(pl);
+#endif /* if SIZEOF_INT == SIZEOF_LONG */
+}
+
+/*
+ * Get X ID (array) property
+ *
+ * At most len items are returned in val.
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_xid_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID *lst,
+ unsigned int len)
+{
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ int num;
+ unsigned i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ prop_ret = NULL;
+ if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ type, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ return -1;
+
+ if (type_ret != type || format_ret != 32)
+ num = -1;
+ else if (num_ret == 0 || !prop_ret)
+ num = 0;
+ else
+ {
+ if (num_ret < len)
+ len = num_ret;
+
+ for (i = 0; i < len; i++)
+ lst[i] = ((unsigned long *)prop_ret)[i];
+ num = len;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return num;
+}
+
+/*
+ * Get X ID (array) property
+ *
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * The returned array must be freed with free().
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_xid_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID **val)
+{
+ unsigned char *prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ Ecore_X_Atom *alst;
+ int num;
+ unsigned i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ *val = NULL;
+ prop_ret = NULL;
+ if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+ type, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret) != Success)
+ return -1;
+
+ if (type_ret != type || format_ret != 32)
+ num = -1;
+ else if (num_ret == 0 || !prop_ret)
+ num = 0;
+ else
+ {
+ alst = malloc(num_ret * sizeof(Ecore_X_ID));
+ for (i = 0; i < num_ret; i++)
+ alst[i] = ((unsigned long *)prop_ret)[i];
+ num = num_ret;
+ *val = alst;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
+
+ return num;
+}
+
+/*
+ * Remove/add/toggle X ID list item.
+ */
+EAPI void
+ecore_x_window_prop_xid_list_change(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom type,
+ Ecore_X_ID item,
+ int op)
+{
+ Ecore_X_ID *lst;
+ int i, num;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst);
+ if (num < 0)
+ {
+ return; /* Error - assuming invalid window */
+ }
+
+ /* Is it there? */
+ for (i = 0; i < num; i++)
+ {
+ if (lst[i] == item)
+ break;
+ }
+
+ if (i < num)
+ {
+ /* Was in list */
+ if (op == ECORE_X_PROP_LIST_ADD)
+ goto done; /* Remove it */
+
+ num--;
+ for (; i < num; i++)
+ lst[i] = lst[i + 1];
+ }
+ else
+ {
+ /* Was not in list */
+ if (op == ECORE_X_PROP_LIST_REMOVE)
+ goto done; /* Add it */
+
+ num++;
+ lst = realloc(lst, num * sizeof(Ecore_X_ID));
+ lst[i] = item;
+ }
+
+ ecore_x_window_prop_xid_set(win, atom, type, lst, num);
+
+done:
+ if (lst)
+ free(lst);
+}
+
+/*
+ * Set Atom (array) property
+ */
+EAPI void
+ecore_x_window_prop_atom_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom *lst,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_xid_set(win, atom, XA_ATOM, lst, num);
+}
+
+/*
+ * Get Atom (array) property
+ *
+ * At most len items are returned in val.
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_atom_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom *lst,
+ unsigned int len)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_window_prop_xid_get(win, atom, XA_ATOM, lst, len);
+}
+
+/*
+ * Get Atom (array) property
+ *
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * The returned array must be freed with free().
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_atom_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom **plst)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_window_prop_xid_list_get(win, atom, XA_ATOM, plst);
+}
+
+/*
+ * Remove/add/toggle atom list item.
+ */
+EAPI void
+ecore_x_window_prop_atom_list_change(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Atom item,
+ int op)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_xid_list_change(win, atom, XA_ATOM, item, op);
+}
+
+/*
+ * Set Window (array) property
+ */
+EAPI void
+ecore_x_window_prop_window_set(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window *lst,
+ unsigned int num)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ ecore_x_window_prop_xid_set(win, atom, XA_WINDOW, lst, num);
+}
+
+/*
+ * Get Window (array) property
+ *
+ * At most len items are returned in val.
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_window_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window *lst,
+ unsigned int len)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_window_prop_xid_get(win, atom, XA_WINDOW, lst, len);
+}
+
+/*
+ * Get Window (array) property
+ *
+ * If the property was successfully fetched the number of items stored in
+ * val is returned, otherwise -1 is returned.
+ * The returned array must be freed with free().
+ * Note: Return value 0 means that the property exists but has no elements.
+ */
+EAPI int
+ecore_x_window_prop_window_list_get(Ecore_X_Window win,
+ Ecore_X_Atom atom,
+ Ecore_X_Window **plst)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ return ecore_x_window_prop_xid_list_get(win, atom, XA_WINDOW, plst);
+}
+
+EAPI Ecore_X_Atom
+ecore_x_window_prop_any_type(void)
+{
+ return AnyPropertyType;
+}
+
+/**
+ * @brief Set a property of Ecore_X_Window.
+ * @param win The window for which the property will be set.
+ * @param property The property of the window to be set.
+ * @param type The type of the property that will be set.
+ * @param size The size of the property that will be set.
+ * @param data The data of the property that will be set.
+ * @param number The size of data.
+ */
+EAPI void
+ecore_x_window_prop_property_set(Ecore_X_Window win,
+ Ecore_X_Atom property,
+ Ecore_X_Atom type,
+ int size,
+ void *data,
+ int number)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ if (size != 32)
+ XChangeProperty(_ecore_x_disp,
+ win,
+ property,
+ type,
+ size,
+ PropModeReplace,
+ (unsigned char *)data,
+ number);
+ else
+ {
+ unsigned long *dat;
+ int i, *ptr;
+
+ dat = malloc(sizeof(unsigned long) * number);
+ if (dat)
+ {
+ for (ptr = (int *)data, i = 0; i < number; i++)
+ dat[i] = ptr[i];
+ XChangeProperty(_ecore_x_disp, win, property, type, size,
+ PropModeReplace, (unsigned char *)dat, number);
+ free(dat);
+ }
+ }
+}
+
+/**
+ * @brief Get a property of Ecore_X_Window.
+ * @note If there aren't any data to be got the function return NULL.
+ * If the function can't allocate the memory then 0 is returned.
+ * @param win The window for which the property will be got.
+ * @param property The property of the window that will be gotten.
+ * @param type The type of the property that will be gotten.
+ * @param size This parameter isn't in use.
+ * @param data The data of the property that will be gotten.
+ * @param num The size of property.
+ * @return size_ret The size of array that contains the property.
+ */
+EAPI int
+ecore_x_window_prop_property_get(Ecore_X_Window win,
+ Ecore_X_Atom property,
+ Ecore_X_Atom type,
+ int size EINA_UNUSED,
+ unsigned char **data,
+ int *num)
+{
+ Atom type_ret = 0;
+ int ret, size_ret = 0;
+ unsigned long num_ret = 0, bytes = 0, i;
+ unsigned char *prop_ret = NULL;
+
+ /* make sure these are initialized */
+ if (num)
+ *num = 0;
+
+ if (data)
+ *data = NULL;
+ else /* we can't store the retrieved data, so just return */
+ return 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!win)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ ret = XGetWindowProperty(_ecore_x_disp, win, property, 0, LONG_MAX,
+ False, type, &type_ret, &size_ret,
+ &num_ret, &bytes, &prop_ret);
+
+ if (ret != Success)
+ return 0;
+
+ if (!num_ret)
+ {
+ XFree(prop_ret);
+ return 0;
+ }
+
+ if (!(*data = malloc(num_ret * size_ret / 8)))
+ {
+ XFree(prop_ret);
+ return 0;
+ }
+
+ switch (size_ret) {
+ case 8:
+ for (i = 0; i < num_ret; i++)
+ (*data)[i] = prop_ret[i];
+ break;
+
+ case 16:
+ for (i = 0; i < num_ret; i++)
+ ((unsigned short *)*data)[i] = ((unsigned short *)prop_ret)[i];
+ break;
+
+ case 32:
+ for (i = 0; i < num_ret; i++)
+ ((unsigned int *)*data)[i] = ((unsigned long *)prop_ret)[i];
+ break;
+ }
+
+ XFree(prop_ret);
+
+ if (num)
+ *num = num_ret;
+
+ return size_ret;
+}
+
+EAPI void
+ecore_x_window_prop_property_del(Ecore_X_Window win,
+ Ecore_X_Atom property)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XDeleteProperty(_ecore_x_disp, win, property);
+}
+
+EAPI Ecore_X_Atom *
+ecore_x_window_prop_list(Ecore_X_Window win,
+ int *num_ret)
+{
+ Ecore_X_Atom *atoms;
+ Atom *atom_ret;
+ int num = 0, i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num_ret)
+ *num_ret = 0;
+
+ atom_ret = XListProperties(_ecore_x_disp, win, &num);
+ if (!atom_ret)
+ return NULL;
+
+ atoms = malloc(num * sizeof(Ecore_X_Atom));
+ if (atoms)
+ {
+ for (i = 0; i < num; i++)
+ atoms[i] = atom_ret[i];
+ if (num_ret)
+ *num_ret = num;
+ }
+
+ XFree(atom_ret);
+ return atoms;
+}
+
+/**
+ * Set a window string property.
+ * @param win The window
+ * @param type The property
+ * @param str The string
+ *
+ * Set a window string property
+ */
+EAPI void
+ecore_x_window_prop_string_set(Ecore_X_Window win,
+ Ecore_X_Atom type,
+ const char *str)
+{
+ XTextProperty xtp;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ xtp.value = (unsigned char *)str;
+ xtp.format = 8;
+ xtp.encoding = ECORE_X_ATOM_UTF8_STRING;
+ xtp.nitems = strlen(str);
+ XSetTextProperty(_ecore_x_disp, win, &xtp, type);
+}
+
+/**
+ * Get a window string property.
+ * @param win The window
+ * @param type The property
+ * @return Window string property of a window. String must be free'd when done.
+ */
+EAPI char *
+ecore_x_window_prop_string_get(Ecore_X_Window win,
+ Ecore_X_Atom type)
+{
+ XTextProperty xtp;
+ char *str = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (win == 0)
+ win = DefaultRootWindow(_ecore_x_disp);
+
+ if (XGetTextProperty(_ecore_x_disp, win, &xtp, type))
+ {
+ int items;
+ char **list = NULL;
+ Status s;
+
+ if (xtp.encoding == ECORE_X_ATOM_UTF8_STRING)
+ str = strdup((char *)xtp.value);
+ else
+ {
+#ifdef X_HAVE_UTF8_STRING
+ s = Xutf8TextPropertyToTextList(_ecore_x_disp, &xtp,
+ &list, &items);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ s = XmbTextPropertyToTextList(_ecore_x_disp, &xtp,
+ &list, &items);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ if ((s == XLocaleNotSupported) ||
+ (s == XNoMemory) || (s == XConverterNotFound))
+ str = strdup((char *)xtp.value);
+ else if ((s >= Success) && (items > 0))
+ str = strdup(list[0]);
+
+ if (list)
+ XFreeStringList(list);
+ }
+
+ XFree(xtp.value);
+ }
+
+ return str;
+}
+
+EAPI Eina_Bool
+ecore_x_window_prop_protocol_isset(Ecore_X_Window win,
+ Ecore_X_WM_Protocol protocol)
+{
+ Atom proto, *protos = NULL;
+ int i, protos_count = 0;
+ Eina_Bool ret = EINA_FALSE;
+
+ /* check for invalid values */
+ if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ proto = _ecore_x_atoms_wm_protocols[protocol];
+
+ if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
+ return ret;
+
+ for (i = 0; i < protos_count; i++)
+ if (protos[i] == proto)
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+
+ XFree(protos);
+
+ return ret;
+}
+
+/**
+ * @brief Get a array containing the protocols of @a win
+ * @note If there aren't any properties to be counted or any protocols to get
+ * then the function returns NULL.
+ * @param win The window for which protocol list will be got.
+ * @param num_ret Contains the number of elements of the array to be returned.
+ * @return The array that contains the protocols.
+ */
+EAPI Ecore_X_WM_Protocol *
+ecore_x_window_prop_protocol_list_get(Ecore_X_Window win,
+ int *num_ret)
+{
+ Atom *protos = NULL;
+ int i, protos_count = 0;
+ Ecore_X_WM_Protocol *prot_ret = NULL;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
+ return NULL;
+
+ if ((!protos) || (protos_count <= 0))
+ return NULL;
+
+ prot_ret = calloc(1, protos_count * sizeof(Ecore_X_WM_Protocol));
+ if (!prot_ret)
+ {
+ XFree(protos);
+ return NULL;
+ }
+
+ for (i = 0; i < protos_count; i++)
+ {
+ Ecore_X_WM_Protocol j;
+
+ prot_ret[i] = -1;
+ for (j = 0; j < ECORE_X_WM_PROTOCOL_NUM; j++)
+ {
+ if (_ecore_x_atoms_wm_protocols[j] == protos[i])
+ prot_ret[i] = j;
+ }
+ }
+ XFree(protos);
+ *num_ret = protos_count;
+ return prot_ret;
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_window_shape.c b/src/lib/ecore_x/xlib/ecore_x_window_shape.c
new file mode 100644
index 0000000000..71718cfa3a
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_window_shape.c
@@ -0,0 +1,658 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+/**
+ * @defgroup Ecore_X_Window_Shape X Window Shape Functions
+ *
+ * These functions use the shape extension of the X server to change
+ * shape of given windows.
+ */
+
+/**
+ * Sets the shape of the given window to that given by the pixmap @p mask.
+ * @param win The given window.
+ * @param mask A 2-bit depth pixmap that provides the new shape of the
+ * window.
+ * @ingroup Ecore_X_Window_Shape
+ */
+EAPI void
+ecore_x_window_shape_mask_set(Ecore_X_Window win,
+ Ecore_X_Pixmap mask)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineMask(_ecore_x_disp, win, ShapeBounding, 0, 0, mask, ShapeSet);
+}
+
+/**
+ * Sets the input shape of the given window to that given by the pixmap @p mask.
+ * @param win The given window.
+ * @param mask A 1-bit depth pixmap that provides the new input shape of the
+ * window.
+ * @ingroup Ecore_X_Window_Shape
+ */
+EAPI void
+ecore_x_window_shape_input_mask_set(Ecore_X_Window win,
+ Ecore_X_Pixmap mask)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+#ifdef ShapeInput
+ XShapeCombineMask(_ecore_x_disp, win, ShapeInput, 0, 0, mask, ShapeSet);
+#else /* ifdef ShapeInput */
+ return;
+ win = mask = 0;
+#endif /* ifdef ShapeInput */
+}
+
+EAPI void
+ecore_x_window_shape_window_set(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ shape_win,
+ ShapeBounding,
+ ShapeSet);
+}
+
+EAPI void
+ecore_x_window_shape_input_window_set(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+#ifdef ShapeInput
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ shape_win,
+ ShapeInput,
+ ShapeSet);
+#else
+ return;
+ win = shape_win = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_set_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ x,
+ y,
+ shape_win,
+ ShapeBounding,
+ ShapeSet);
+}
+
+EAPI void
+ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+#ifdef ShapeInput
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeInput,
+ x,
+ y,
+ shape_win,
+ ShapeInput,
+ ShapeSet);
+#else
+ return;
+ win = shape_win = x = y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeSet,
+ Unsorted);
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ShapeInput
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeSet,
+ Unsorted);
+#else
+ return;
+ win = x = y = w = h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangles_set(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ShapeInput
+ XRectangle *rect = NULL;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!rects) return;
+ if (num > 0)
+ {
+ rect = malloc(sizeof(XRectangle) * num);
+ if (!rect) return;
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ rect,
+ num,
+ ShapeSet,
+ Unsorted);
+ if (rect) free(rect);
+#else
+ return;
+ win = rects = num = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ShapeInput
+ XRectangle *rect = NULL;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (!rects) return;
+ if (num > 0)
+ {
+ rect = malloc(sizeof(XRectangle) * num);
+ if (!rect) return;
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ rect,
+ num,
+ ShapeSet,
+ Unsorted);
+ if (rect) free(rect);
+#else
+ return;
+ win = rects = num = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeSubtract,
+ Unsorted);
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ShapeInput
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeSubtract,
+ Unsorted);
+#else
+ return;
+ win = x = y = w = h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_window_add(Ecore_X_Window win,
+ Ecore_X_Window shape_win)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ shape_win,
+ ShapeBounding,
+ ShapeUnion);
+}
+
+EAPI void
+ecore_x_window_shape_window_add_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ x,
+ y,
+ shape_win,
+ ShapeBounding,
+ ShapeUnion);
+}
+
+EAPI void
+ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win,
+ Ecore_X_Window shape_win,
+ int x,
+ int y)
+{
+#ifdef ShapeInput
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ XShapeCombineShape(_ecore_x_disp,
+ win,
+ ShapeInput,
+ x,
+ y,
+ shape_win,
+ ShapeInput,
+ ShapeUnion);
+#else
+ return;
+ win = shape_win = x = y = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_add(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeUnion,
+ Unsorted);
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ShapeInput
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeUnion,
+ Unsorted);
+#else
+ return;
+ win = x = y = w = h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangle_clip(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeIntersect,
+ Unsorted);
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+#ifdef ShapeInput
+ XRectangle rect;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ &rect,
+ 1,
+ ShapeIntersect,
+ Unsorted);
+#else
+ return;
+ win = x = y = w = h = 0;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_rectangles_add(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+ XRectangle *rect = NULL;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num > 0)
+ {
+ rect = malloc(sizeof(XRectangle) * num);
+ if (!rect) return;
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeBounding,
+ 0,
+ 0,
+ rect,
+ num,
+ ShapeUnion,
+ Unsorted);
+ if (rect) free(rect);
+}
+
+EAPI void
+ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win,
+ Ecore_X_Rectangle *rects,
+ int num)
+{
+#ifdef ShapeInput
+ XRectangle *rect = NULL;
+ int i;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (num > 0)
+ {
+ rect = malloc(sizeof(XRectangle) * num);
+ if (!rect) return;
+ for (i = 0; i < num; i++)
+ {
+ rect[i].x = rects[i].x;
+ rect[i].y = rects[i].y;
+ rect[i].width = rects[i].width;
+ rect[i].height = rects[i].height;
+ }
+ }
+
+ XShapeCombineRectangles(_ecore_x_disp,
+ win,
+ ShapeInput,
+ 0,
+ 0,
+ rect,
+ num,
+ ShapeUnion,
+ Unsorted);
+ if (rect) free(rect);
+#else
+ return;
+ win = rects = num = 0;
+#endif
+}
+
+EAPI Ecore_X_Rectangle *
+ecore_x_window_shape_rectangles_get(Ecore_X_Window win,
+ int *num_ret)
+{
+ XRectangle *rect;
+ Ecore_X_Rectangle *rects = NULL;
+ int i, num = 0, ord;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect = XShapeGetRectangles(_ecore_x_disp, win, ShapeBounding, &num, &ord);
+ if (rect)
+ {
+ if (num < 1)
+ {
+ XFree(rect);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ rects = malloc(sizeof(Ecore_X_Rectangle) * num);
+ if (!rects)
+ {
+ XFree(rect);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ for (i = 0; i < num; i++)
+ {
+ rects[i].x = rect[i].x;
+ rects[i].y = rect[i].y;
+ rects[i].width = rect[i].width;
+ rects[i].height = rect[i].height;
+ }
+ XFree(rect);
+ }
+ if (num_ret) *num_ret = num;
+ return rects;
+}
+
+EAPI Ecore_X_Rectangle *
+ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win,
+ int *num_ret)
+{
+ Ecore_X_Rectangle *rects = NULL;
+#ifdef ShapeInput
+ XRectangle *rect;
+ int i, num = 0, ord;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ rect = XShapeGetRectangles(_ecore_x_disp, win, ShapeInput, &num, &ord);
+ if (rect)
+ {
+ if (num < 1)
+ {
+ XFree(rect);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ rects = malloc(sizeof(Ecore_X_Rectangle) * num);
+ if (!rects)
+ {
+ XFree(rect);
+ if (num_ret) *num_ret = 0;
+ return NULL;
+ }
+ for (i = 0; i < num; i++)
+ {
+ rects[i].x = rect[i].x;
+ rects[i].y = rect[i].y;
+ rects[i].width = rect[i].width;
+ rects[i].height = rect[i].height;
+ }
+ XFree(rect);
+ }
+ if (num_ret) *num_ret = num;
+ return rects;
+#else
+ // have to return fake shape input rect of size of window
+ Window dw;
+ unsigned int di;
+
+ if (num_ret) *num_ret = 0;
+ rects = malloc(sizeof(Ecore_X_Rectangle));
+ if (!rects) return NULL;
+ if (!XGetGeometry(_ecore_x_disp, win, &dw,
+ &(rects[0].x), &(rects[0].y),
+ &(rects[0].width), &(rects[0].height),
+ &di, &di))
+ {
+ free(rects);
+ return NULL;
+ }
+ if (num_ret) *num_ret = 1;
+ return rects;
+#endif
+}
+
+EAPI void
+ecore_x_window_shape_events_select(Ecore_X_Window win,
+ Eina_Bool on)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (on)
+ XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask);
+ else
+ XShapeSelectInput(_ecore_x_disp, win, 0);
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_xi2.c b/src/lib/ecore_x/xlib/ecore_x_xi2.c
new file mode 100644
index 0000000000..04d1023ec7
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_xi2.c
@@ -0,0 +1,336 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+
+#ifdef ECORE_XI2
+#include "Ecore_Input.h"
+#endif /* ifdef ECORE_XI2 */
+
+int _ecore_x_xi2_opcode = -1;
+
+#ifndef XIPointerEmulated
+#define XIPointerEmulated (1 << 16)
+#endif
+
+#ifdef ECORE_XI2
+static XIDeviceInfo *_ecore_x_xi2_devs = NULL;
+static int _ecore_x_xi2_num = 0;
+#endif /* ifdef ECORE_XI2 */
+
+void
+_ecore_x_input_init(void)
+{
+#ifdef ECORE_XI2
+ int event, error;
+ int major = 2, minor = 0;
+
+ if (!XQueryExtension(_ecore_x_disp, "XInputExtension",
+ &_ecore_x_xi2_opcode, &event, &error))
+ {
+ _ecore_x_xi2_opcode = -1;
+ return;
+ }
+
+ if (XIQueryVersion(_ecore_x_disp, &major, &minor) == BadRequest)
+ {
+ _ecore_x_xi2_opcode = -1;
+ return;
+ }
+
+ _ecore_x_xi2_devs = XIQueryDevice(_ecore_x_disp, XIAllDevices,
+ &_ecore_x_xi2_num);
+#endif /* ifdef ECORE_XI2 */
+}
+
+void
+_ecore_x_input_shutdown(void)
+{
+#ifdef ECORE_XI2
+ if (_ecore_x_xi2_devs)
+ {
+ XIFreeDeviceInfo(_ecore_x_xi2_devs);
+ _ecore_x_xi2_devs = NULL;
+ }
+
+ _ecore_x_xi2_num = 0;
+ _ecore_x_xi2_opcode = -1;
+#endif /* ifdef ECORE_XI2 */
+}
+
+void
+_ecore_x_input_handler(XEvent *xevent)
+{
+#ifdef ECORE_XI2
+ XIDeviceEvent *evd = (XIDeviceEvent *)(xevent->xcookie.data);
+ /* XIRawEvent *evr = (XIRawEvent *)(xevent->xcookie.data); */
+ int devid = evd->deviceid;
+ int i;
+
+ /* No filter for this events */
+ switch (xevent->xcookie.evtype)
+ {
+#ifdef XI_RawButtonPress
+ case XI_RawButtonPress:
+ ecore_event_add(ECORE_X_RAW_BUTTON_PRESS, NULL, NULL, NULL);
+ break;
+#endif
+#ifdef XI_RawButtonRelease
+ case XI_RawButtonRelease:
+ ecore_event_add(ECORE_X_RAW_BUTTON_RELEASE, NULL, NULL, NULL);
+ break;
+#endif
+#ifdef XI_RawMotion
+ case XI_RawMotion:
+ ecore_event_add(ECORE_X_RAW_MOTION, NULL, NULL, NULL);
+ break;
+#endif
+ }
+
+ if (_ecore_x_xi2_devs)
+ {
+ for (i = 0; i < _ecore_x_xi2_num; i++)
+ {
+ XIDeviceInfo *dev = &(_ecore_x_xi2_devs[i]);
+
+ if (devid == dev->deviceid)
+ {
+ if (dev->use == XIMasterPointer) return;
+ if ((dev->use == XISlavePointer) &&
+ (evd->flags & XIPointerEmulated)) return;
+ }
+ }
+ }
+ switch (xevent->xcookie.evtype)
+ {
+ case XI_Motion:
+ _ecore_mouse_move
+ (evd->time,
+ 0, // state
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+ case XI_ButtonPress:
+ _ecore_mouse_button
+ (ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ evd->time,
+ 0, // state
+ 0, // button
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+ case XI_ButtonRelease:
+ _ecore_mouse_button
+ (ECORE_EVENT_MOUSE_BUTTON_UP,
+ evd->time,
+ 0, // state
+ 0, // button
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+#ifdef XI_TouchUpdate
+ case XI_TouchUpdate:
+ _ecore_mouse_move
+ (evd->time,
+ 0, // state
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+#endif
+#ifdef XI_TouchBegin
+ case XI_TouchBegin:
+ _ecore_mouse_button
+ (ECORE_EVENT_MOUSE_BUTTON_DOWN,
+ evd->time,
+ 0, // state
+ 0, // button
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+#endif
+#ifdef XI_TouchEnd
+ case XI_TouchEnd:
+ _ecore_mouse_button
+ (ECORE_EVENT_MOUSE_BUTTON_UP,
+ evd->time,
+ 0, // state
+ 0, // button
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y,
+ evd->event,
+ (evd->child ? evd->child : evd->event),
+ evd->root,
+ 1, // same_screen
+ devid, 1, 1,
+ 1.0, // pressure
+ 0.0, // angle
+ evd->event_x, evd->event_y,
+ evd->root_x, evd->root_y);
+ break;
+
+#endif
+ default:
+ break;
+ }
+#endif /* ifdef ECORE_XI2 */
+}
+
+EAPI Eina_Bool
+ecore_x_input_multi_select(Ecore_X_Window win)
+{
+#ifdef ECORE_XI2
+ int i;
+ Eina_Bool find = EINA_FALSE;
+
+ if (!_ecore_x_xi2_devs)
+ return 0;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ for (i = 0; i < _ecore_x_xi2_num; i++)
+ {
+ XIDeviceInfo *dev = &(_ecore_x_xi2_devs[i]);
+
+ if (dev->use == XIFloatingSlave)
+ {
+ XIEventMask eventmask;
+ unsigned char mask[4] = { 0 };
+
+ eventmask.deviceid = dev->deviceid;
+ eventmask.mask_len = sizeof(mask);
+ eventmask.mask = mask;
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_Motion);
+ XISelectEvents(_ecore_x_disp, win, &eventmask, 1);
+ find = EINA_TRUE;
+ }
+ else if (dev->use == XISlavePointer)
+ {
+ XIDeviceInfo *atdev = NULL;
+ int j;
+
+ for (j = 0; j < _ecore_x_xi2_num; j++)
+ {
+ if (_ecore_x_xi2_devs[j].deviceid == dev->attachment)
+ atdev = &(_ecore_x_xi2_devs[j]);
+ }
+ if (((atdev) && (atdev->use != XIMasterPointer)) ||
+ (!atdev))
+ {
+ XIEventMask eventmask;
+ unsigned char mask[4] = { 0 };
+
+ eventmask.deviceid = dev->deviceid;
+ eventmask.mask_len = sizeof(mask);
+ eventmask.mask = mask;
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_Motion);
+# ifdef XI_TouchUpdate
+ XISetMask(mask, XI_TouchUpdate);
+# endif
+# ifdef XI_TouchBegin
+ XISetMask(mask, XI_TouchBegin);
+# endif
+# ifdef XI_TouchEnd
+ XISetMask(mask, XI_TouchEnd);
+# endif
+ XISelectEvents(_ecore_x_disp, win, &eventmask, 1);
+ find = EINA_TRUE;
+ }
+ }
+ }
+
+ return find;
+#else /* ifdef ECORE_XI2 */
+ return EINA_FALSE;
+#endif /* ifdef ECORE_XI2 */
+}
+
+EAPI Eina_Bool
+ecore_x_input_raw_select(Ecore_X_Window win)
+{
+#ifdef ECORE_XI2
+ XIEventMask emask;
+ unsigned char mask[4] = { 0 };
+
+ if (!_ecore_x_xi2_devs)
+ return EINA_FALSE;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ emask.deviceid = XIAllMasterDevices;
+ emask.mask_len = sizeof(mask);
+ emask.mask = mask;
+#ifdef XI_RawButtonPress
+ XISetMask(emask.mask, XI_RawButtonPress);
+#endif
+#ifdef XI_RawButtonRelease
+ XISetMask(emask.mask, XI_RawButtonRelease);
+#endif
+#ifdef XI_RawMotion
+ XISetMask(emask.mask, XI_RawMotion);
+#endif
+
+ XISelectEvents(_ecore_x_disp, win, &emask, 1);
+
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+#endif
+}
+
diff --git a/src/lib/ecore_x/xlib/ecore_x_xinerama.c b/src/lib/ecore_x/xlib/ecore_x_xinerama.c
new file mode 100644
index 0000000000..f49a4d348f
--- /dev/null
+++ b/src/lib/ecore_x/xlib/ecore_x_xinerama.c
@@ -0,0 +1,91 @@
+/*
+ * Xinerama code
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include "Ecore.h"
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+#ifdef ECORE_XINERAMA
+static XineramaScreenInfo *_xin_info = NULL;
+static int _xin_scr_num = 0;
+#endif /* ifdef ECORE_XINERAMA */
+
+EAPI int
+ecore_x_xinerama_screen_count_get(void)
+{
+#ifdef ECORE_XINERAMA
+ int event_base, error_base;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+ if (_xin_info)
+ XFree(_xin_info);
+
+ _xin_info = NULL;
+ if (XineramaQueryExtension(_ecore_x_disp, &event_base, &error_base))
+ {
+ _xin_info = XineramaQueryScreens(_ecore_x_disp, &_xin_scr_num);
+ if (_xin_info)
+ return _xin_scr_num;
+ }
+
+#endif /* ifdef ECORE_XINERAMA */
+ return 0;
+}
+
+EAPI Eina_Bool
+ecore_x_xinerama_screen_geometry_get(int screen,
+ int *x,
+ int *y,
+ int *w,
+ int *h)
+{
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
+#ifdef ECORE_XINERAMA
+ if (_xin_info)
+ {
+ int i;
+
+ for (i = 0; i < _xin_scr_num; i++)
+ {
+ if (_xin_info[i].screen_number == screen)
+ {
+ if (x)
+ *x = _xin_info[i].x_org;
+
+ if (y)
+ *y = _xin_info[i].y_org;
+
+ if (w)
+ *w = _xin_info[i].width;
+
+ if (h)
+ *h = _xin_info[i].height;
+
+ return EINA_TRUE;
+ }
+ }
+ }
+
+#endif /* ifdef ECORE_XINERAMA */
+ if (x)
+ *x = 0;
+
+ if (y)
+ *y = 0;
+
+ if (w)
+ *w = DisplayWidth(_ecore_x_disp, 0);
+
+ if (h)
+ *h = DisplayHeight(_ecore_x_disp, 0);
+
+ return EINA_FALSE;
+ screen = 0;
+}
+
diff --git a/src/lib/escape/Escape.h b/src/lib/escape/Escape.h
new file mode 100644
index 0000000000..ca728b50b7
--- /dev/null
+++ b/src/lib/escape/Escape.h
@@ -0,0 +1,52 @@
+#ifndef __ESCAPE_H__
+#define __ESCAPE_H__
+
+#ifndef EAPI
+#define EAPI
+#endif /* EAPI */
+#define __UNUSED__ __attribute__((unused))
+
+#include <unistd.h>
+
+#ifdef CLOCK_REALTIME
+#undef CLOCK_REALTIME
+#endif
+#ifdef CLOCK_PROF
+#undef CLOCK_PROF
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+#undef CLOCK_PROCESS_CPUTIME_ID
+#endif
+
+/**
+ * @mainpage Escape
+ * @image html e_big.png
+ * @author Youness Alaoui
+ * @date 2011
+ *
+ * @section intro_sec Introduction
+ *
+ * The Escape library is a library that acts implements some of the missing
+ * function from the PS3 GameOS system that are needed for the proper
+ * functioning of the EFL.
+ *
+ * @section escape_sec Escape API Documentation
+ *
+ * Take a look at the documentation of @ref mmap/munmap.
+ *
+ */
+
+#include "escape_libgen.h"
+#include "escape_unistd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Nothing to see here */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESCAPE_H__ */
diff --git a/src/lib/escape/escape_libgen.c b/src/lib/escape/escape_libgen.c
new file mode 100644
index 0000000000..796708978e
--- /dev/null
+++ b/src/lib/escape/escape_libgen.c
@@ -0,0 +1,90 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <malloc.h>
+
+#include "Escape.h"
+
+static char _escape_basename_buf[PATH_MAX];
+static char _escape_dirname_buf[PATH_MAX];
+
+char *
+escape_basename(char *path)
+{
+ char *p1;
+ char *p2;
+ size_t length;
+
+ /* path must begin by "?:\" or "?:/" */
+ if (!path || strlen(path) <= 1)
+ {
+ memcpy(_escape_basename_buf, path, PATH_MAX);
+ return _escape_basename_buf;
+ }
+
+ length = strlen(path);
+ p1 = strdup(path);
+ if (!p1)
+ {
+ memcpy(_escape_basename_buf, path, PATH_MAX);
+ return _escape_basename_buf;
+ }
+
+ /* remove trailing backslashes */
+ p2 = p1 + (length - 1);
+ if (*p2 == '/')
+ {
+ while (*p2 == '/')
+ p2--;
+ }
+ *(p2 + 1) = '\0';
+
+ p2 = strrchr(p1, '/');
+ memcpy(_escape_basename_buf, p2 + 1, (p1 + length + 1) - p2);
+
+ free(p1);
+
+ return _escape_basename_buf;
+}
+
+char *
+escape_dirname(char *path)
+{
+ char *p1;
+ char *p2;
+ size_t length;
+
+ /* path must begin by "?:\" or "?:/" */
+ if (!path || strlen(path) <= 1)
+ {
+ memcpy(_escape_dirname_buf, path, PATH_MAX);
+ return _escape_dirname_buf;
+ }
+
+ length = strlen(path);
+ p1 = strdup(path);
+ if (!p1)
+ {
+ memcpy(_escape_dirname_buf, path, PATH_MAX);
+ return _escape_dirname_buf;
+ }
+ /* remove trailing backslashes */
+ p2 = p1 + (length - 1);
+ if (*p2 == '/')
+ {
+ while (*p2 == '/')
+ p2--;
+ }
+ *(p2 + 1) = '\0';
+
+ p2 = strrchr(p1, '/');
+ *p2 = '\0';
+ memcpy(_escape_dirname_buf, p1, strlen(p1) + 1);
+
+ free(p1);
+
+ return _escape_dirname_buf;
+}
+
diff --git a/src/lib/escape/escape_libgen.h b/src/lib/escape/escape_libgen.h
new file mode 100644
index 0000000000..0c23a76821
--- /dev/null
+++ b/src/lib/escape/escape_libgen.h
@@ -0,0 +1,32 @@
+#ifndef __ESCAPE_LIBGEN_H__
+#define __ESCAPE_LIBGEN_H__
+
+/**
+ * @file escape_libgen.h
+ * @brief The file that provides functions ported from Unix in libgen.h.
+ * @defgroup Escape_Libgen_Group Libgen.h functions.
+ *
+ * This header provides functions ported from Unix in libgen.h.
+ *
+ * @{
+ */
+
+EAPI char *escape_basename(char *path);
+
+#ifdef basename
+#undef basename
+#endif
+#define basename(p) escape_basename(p)
+
+EAPI char *escape_dirname(char *path);
+
+#ifdef dirname
+#undef dirname
+#endif
+#define dirname(p) escape_dirname(p)
+
+/**
+ * @}
+ */
+
+#endif /* __ESCAPE_LIBGEN_H__ */
diff --git a/src/lib/escape/escape_mman.c b/src/lib/escape/escape_mman.c
new file mode 100644
index 0000000000..995c72e7f4
--- /dev/null
+++ b/src/lib/escape/escape_mman.c
@@ -0,0 +1,67 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sys/mman.h"
+
+/***** API *****/
+
+void *
+mmap(void *addr __UNUSED__,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset)
+{
+ void *data;
+ size_t size;
+
+ data = malloc(len);
+ if (!data)
+ {
+ fprintf (stderr, "[Escape] [mmap] malloc failed\n");
+ return MAP_FAILED;
+ }
+
+ size = read(fd, data, len);
+ if (size != len)
+ {
+ fprintf (stderr, "[Escape] [mmap] read failed\n");
+ free(data);
+ return MAP_FAILED;
+ }
+
+ if (lseek(fd, -len, SEEK_CUR) == -1)
+ {
+ fprintf (stderr, "[Escape] [mmap] lseek failed\n");
+ free(data);
+ return MAP_FAILED;
+ }
+
+ return data;
+}
+
+int
+munmap(void *addr,
+ size_t len __UNUSED__)
+{
+ if (addr && (addr != MAP_FAILED))
+ free(addr);
+
+ return 0;
+}
+
+int
+madvise(void *addr __UNUSED__,
+ size_t length __UNUSED__,
+ int advice __UNUSED__)
+{
+ return 0;
+}
+
diff --git a/src/lib/escape/escape_unistd.c b/src/lib/escape/escape_unistd.c
new file mode 100644
index 0000000000..5dbbb18634
--- /dev/null
+++ b/src/lib/escape/escape_unistd.c
@@ -0,0 +1,186 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#include <sys/types.h> /* See NOTES */
+#include <sys/socket.h>
+#include <net/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/net.h>
+#include <string.h>
+#include <libiberty.h>
+#include <sys/stat.h>
+
+#include "Escape.h"
+
+char *
+escape_realpath(const char *path, char *resolved_path)
+{
+ char *real = lrealpath (path);
+
+ if (real)
+ {
+ if (resolved_path)
+ {
+ memcpy (resolved_path, real, PATH_MAX);
+ free (real);
+ return resolved_path;
+ }
+ else
+ {
+ return real;
+ }
+ }
+
+ return NULL;
+}
+
+int
+escape_access(const char *pathname, int mode)
+{
+ struct stat stat_buf;
+
+ if (stat(pathname, &stat_buf) != 0)
+ return -1;
+
+ if (mode == F_OK)
+ return 0;
+ if (mode == R_OK)
+ {
+ if (stat_buf.st_mode & S_IRUSR)
+ return 0;
+ errno = EACCES;
+ return -1;
+ }
+ if (mode == W_OK)
+ {
+ if (stat_buf.st_mode & S_IWUSR)
+ return 0;
+ errno = EROFS;
+ return -1;
+ }
+ if (mode == X_OK)
+ {
+ if (stat_buf.st_mode & S_IXUSR)
+ return 0;
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
+
+EAPI ssize_t
+escape_readlink(const char *path,
+ char *buf,
+ size_t bufsize)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+EAPI int
+escape_symlink(const char *path1, const char *path2)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * The code of the following functions has been kindly offered
+ * by Tor Lillqvist.
+ */
+int
+escape_pipe(int *fds)
+{
+ struct sockaddr_in saddr;
+ int temp;
+ int socket1 = -1;
+ int socket2 = -1;
+ fd_set read_set;
+ fd_set write_set;
+ int len;
+
+ temp = socket (AF_INET, SOCK_STREAM, 0);
+
+ if (temp == -1)
+ goto out0;
+
+ memset (&saddr, 0, sizeof (saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0;
+ saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)))
+ goto out0;
+
+ if (listen (temp, 1) == -1)
+ goto out0;
+
+ len = sizeof (saddr);
+ if (getsockname (temp, (struct sockaddr *)&saddr, &len))
+ goto out0;
+
+ socket1 = socket (AF_INET, SOCK_STREAM, 0);
+
+ if (socket1 == -1)
+ goto out0;
+
+ if ((connect (socket1, (struct sockaddr *)&saddr, len) == -1) &&
+ (errno != EAGAIN))
+ goto out1;
+
+ FD_ZERO (&read_set);
+ FD_SET (temp, &read_set);
+
+ if (select (0, &read_set, NULL, NULL, NULL) == -1)
+ goto out1;
+
+ if (!FD_ISSET (temp, &read_set))
+ goto out1;
+
+ socket2 = accept (temp, (struct sockaddr *)&saddr, &len);
+ if (socket2 == -1)
+ goto out1;
+
+ FD_ZERO (&write_set);
+ FD_SET (socket1, &write_set);
+
+ if (select (0, NULL, &write_set, NULL, NULL) == -1)
+ goto out2;
+
+ if (!FD_ISSET (socket1, &write_set))
+ goto out2;
+
+ fds[0] = socket1;
+ fds[1] = socket2;
+
+ closesocket (temp);
+
+ return 0;
+
+out2:
+ closesocket (socket2);
+out1:
+ closesocket (socket1);
+out0:
+ closesocket (temp);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return -1;
+}
+
+#undef access
+int
+access(const char *pathname, int mode)
+{
+ return escape_access (pathname, mode);
+}
+
diff --git a/src/lib/escape/escape_unistd.h b/src/lib/escape/escape_unistd.h
new file mode 100644
index 0000000000..0e96d3f3cb
--- /dev/null
+++ b/src/lib/escape/escape_unistd.h
@@ -0,0 +1,107 @@
+#ifndef __ESCAPE_UNISTD_H__
+#define __ESCAPE_UNISTD_H__
+
+/**
+ * @file escape_unistd.h
+ * @brief The file that provides functions ported from Unix in unistd.h.
+ * @defgroup Escape_Unistd_Group Unistd.h functions
+ *
+ * This header provides functions ported from Unix in unistd.h.
+ *
+ * @{
+ */
+
+#include <sys/syslimits.h>
+
+/* Path function */
+/**
+ * @brief return the canonicalized absolute pathname
+ *
+ * @param path A path to canonicalize
+ * @param resolved_path A pointer of size PATH_MAX where to store the result
+ *
+ * realpath() expands all symbolic links and resolves references to /./, /../
+ * and extra '/' characters in the null-terminated string named by path to
+ * produce a canonicalized absolute pathname. The resulting pathname is
+ * stored as a null-terminated string, up to a maximum of PATH_MAX bytes,
+ * in the buffer pointed to by resolved_path. The resulting path will have
+ * no symbolic link, /./ or /../ components.
+ *
+ * If resolved_path is specified as NULL, then realpath() uses malloc(3)
+ * to allocate a buffer of up to PATH_MAX bytes to hold the resolved pathname,
+ * and returns a pointer to this buffer.
+ * The caller should deallocate this buffer using free(3).
+ *
+ */
+EAPI char *escape_realpath(const char *path, char *resolved_path);
+#ifdef realpath
+#undef realpath
+#endif
+#define realpath escape_realpath
+
+EAPI ssize_t
+escape_readlink(const char *path,
+ char *buf,
+ size_t bufsize);
+#ifdef readlink
+#undef readlink
+#endif
+#define readlink escape_readlink
+
+EAPI int
+escape_symlink(const char *path1, const char *path2);
+#ifdef symlink
+#undef symlink
+#endif
+#define symlink escape_symlink
+
+/**
+ * @brief check real user's permissions for a file
+ *
+ * @param pathname The path to check
+ * @param mode the permission to check
+ *
+ * access() checks whether the calling process can access the file pathname.
+ * If pathname is a symbolic link, it is dereferenced.
+ * The mode specifies the accessibility check(s) to be performed, and is either
+ * the value F_OK, or a mask consisting of the bitwise OR of one or more
+ * of R_OK, W_OK, and X_OK. F_OK tests for the existence of the file.
+ * R_OK, W_OK, and X_OK test whether the file exists and grants read, write,
+ * and execute permissions, respectively.
+ *
+ */
+EAPI int
+escape_access(const char *pathname, int mode);
+#ifdef access
+#undef access
+#endif
+#define access escape_access
+
+/**
+ * @brief Create a pair of sockets.
+ *
+ * @param fds A pointer that contains two sockets.
+ *
+ * Create a pair of sockets that can be use with select().
+ * Contrary to Unix, that functions does not
+ * create a pair of file descriptors.
+ *
+ * Conformity: Not applicable.
+ */
+EAPI int
+escape_pipe(int *fds);
+
+/**
+ * @def pipe(fds)
+ *
+ * Wrapper around escape_pipe().
+ */
+#define pipe(fds) escape_pipe(fds)
+
+//#define sync()
+
+/**
+ * @}
+ */
+
+#endif /* __ESCAPE_UNISTD_H__ */
diff --git a/src/lib/escape/sys/mman.h b/src/lib/escape/sys/mman.h
new file mode 100644
index 0000000000..98ef7fa5fc
--- /dev/null
+++ b/src/lib/escape/sys/mman.h
@@ -0,0 +1,179 @@
+#ifndef __ESCAPE_SYS_MMAN_H__
+#define __ESCAPE_SYS_MMAN_H__
+
+#include <Escape.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @def PROT_NONE
+ * Data can not be accessed.
+ */
+
+/**
+ * @def PROT_READ
+ * Data can be read.
+ */
+
+/**
+ * @def PROT_WRITE
+ * Data can be written.
+ */
+
+/**
+ * @def PROT_EXEC
+ * Data can be executed.
+ */
+
+#define PROT_NONE 0x00
+#define PROT_READ 0x01
+#define PROT_WRITE 0x02
+#define PROT_EXEC 0x04
+
+/**
+ * @def MAP_SHARED
+ * Changes are shared.
+ */
+
+/**
+ * @def MAP_PRIVATE
+ * Changes are private.
+ */
+
+/**
+ * @def MAP_FIXED
+ * Interpret the address (addr) exactly.
+ */
+
+/**
+ * @def MAP_FAILED
+ * Error return from mmap().
+ */
+
+#define MAP_SHARED 0x0001
+#define MAP_PRIVATE 0x0002
+#define MAP_FIXED 0x0010
+
+#define MAP_FAILED ((void *)-1)
+
+/**
+ * @file mman.h
+ * @brief The file that provides the memory map functions
+ * @defgroup Mman Functions that manage memory mappping.
+ *
+ * This header provides the meomry map functions mmap and munmap.
+ *
+ */
+
+/**
+ * Creates or opens a named or unnamed file mapping object for a
+ * specified file and maps a view of a file mapping into the
+ * address space of a calling process.
+ *
+ * @param addr Unused
+ * @param len Number of bytes to be mapped.
+ * @param prot Protections.
+ * @param flags Type of the mapped object.
+ * @param fd File descriptor that describes the object to map.
+ * @param offset Number of bytes from which to start the mapping.
+ * @return The starting address of the mapped view on success, -1 otherwise.
+ *
+ * Create or open an unnamed file mapping object for a specified
+ * file described by the file descriptor @p fd. The number of
+ * bytes that are mapped is given by @p len and start after
+ * @p offset bytes. The parameter @p addr is unused.
+ *
+ * The only type of the mapped object that is supported is
+ * @c MAP_SHARED. If another value if given, -1 is returned.
+ *
+ * @p prot specifies the protection of the mapped region. If
+ * PROT_EXEC is used, it set the execute access. If PROT_READ
+ * is used, it sets the read access. If PROT_WRITE is used, it
+ * sets the write access.
+ *
+ * If the map view of file can not be created, -1 is returned.
+ * If the mappping can not be done, -1 is returned.
+ *
+ * If no error occured, the starting address of the mapped view
+ * is returned.
+ *
+ * Conformity: None.
+ *
+ * @ingroup Mman
+ */
+EAPI void *mmap(void *addr,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset);
+
+/**
+ * Unmaps a mapped view of a file from the calling process's
+ * address space.
+ *
+ * @param addr Pointer to the base address.
+ * @param len Unused.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Unmaps a mapped view of a file from the calling process's
+ * address space. @p addr is the pointer to the base address.
+ * This value must be identical to the value returned by a
+ * previous call to mmap(). The parameter @p len is unsed.
+ *
+ * Conformity: None.
+ *
+ * @ingroup Mman
+ */
+EAPI int
+munmap(void *addr,
+ size_t len);
+
+# define MADV_NORMAL 0 /* No further special treatment. */
+# define MADV_RANDOM 1 /* Expect random page references. */
+# define MADV_SEQUENTIAL 2 /* Expect sequential page references. */
+# define MADV_WILLNEED 3 /* Will need these pages. */
+# define MADV_DONTNEED 4 /* Don't need these pages. */
+# define MADV_REMOVE 9 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
+# define MADV_MERGEABLE 12 /* KSM may merge identical pages. */
+# define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages. */
+# define MADV_HUGEPAGE 14 /* Worth backing with hugepages. */
+# define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages. */
+# define MADV_HWPOISON 100 /* Poison a page for testing. */
+
+/**
+ * give advice about use of memory
+ *
+ * @param addr Unused.
+ * @param length Unused.
+ * @param advice Unused.
+ * @return 0 on success, -1 otherwise.
+ *
+ * The madvise() system call advises the kernel about how to handle
+ * paging input/output in the address range beginning at address addr and
+ * with size length bytes. It allows an application to tell the kernel
+ * how it expects to use some mapped or shared memory areas, so that
+ * the kernel can choose appropriate read-ahead and caching techniques.
+ * This call does not influence the semantics of the application (except
+ * in the case of MADV_DONTNEED), but may influence its performance.
+ * The kernel is free to ignore the advice.
+
+ * Conformity: None.
+ *
+ * @ingroup Mman
+ */
+EAPI int
+madvise(void *addr,
+ size_t length,
+ int advice);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESCAPE_SYS_MMAN_H__ */
+
diff --git a/src/modules/ecore/immodules/ibus/ibus_imcontext.c b/src/modules/ecore/immodules/ibus/ibus_imcontext.c
new file mode 100644
index 0000000000..02f4fce9c1
--- /dev/null
+++ b/src/modules/ecore/immodules/ibus/ibus_imcontext.c
@@ -0,0 +1,822 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include <X11/Xlib.h>
+#include <Ecore_X.h>
+#include <Ecore_Evas.h>
+
+#include <ibus.h>
+#include "ibus_imcontext.h"
+
+struct _IBusIMContext
+{
+ /* instance members */
+ Ecore_IMF_Context *ctx;
+
+ /* enabled */
+ Eina_Bool enable;
+ IBusInputContext *ibuscontext;
+
+ /* preedit status */
+ char *preedit_string;
+ Eina_List *preedit_attrs;
+ int preedit_cursor_pos;
+ Eina_Bool preedit_visible;
+
+ int cursor_x;
+ int cursor_y;
+ int cursor_w;
+ int cursor_h;
+
+ Eina_Bool has_focus;
+
+ Ecore_X_Window client_window;
+ Evas *client_canvas;
+
+ int caps;
+};
+
+typedef struct _KeyEvent KeyEvent;
+
+struct _KeyEvent
+{
+ int keysym;
+ int state;
+};
+
+static Eina_Bool _use_sync_mode = EINA_FALSE;
+
+static Ecore_IMF_Context *_focus_im_context = NULL;
+static IBusBus *_bus = NULL;
+
+/* functions prototype */
+/* static methods*/
+static void _create_input_context (IBusIMContext *context);
+static void _set_cursor_location_internal
+(Ecore_IMF_Context *ctx);
+static void _bus_connected_cb (IBusBus *bus,
+ IBusIMContext *context);
+static XKeyEvent createXKeyEvent (Window win, Eina_Bool press, int keysym, int modifiers);
+
+static void
+_window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
+{
+ Ecore_X_Window root_window, win;
+ int win_x, win_y;
+ int sum_x = 0, sum_y = 0;
+
+ root_window = ecore_x_window_root_get(client_win);
+ win = client_win;
+
+ while (root_window != win)
+ {
+ ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
+ sum_x += win_x;
+ sum_y += win_y;
+ win = ecore_x_window_parent_get(win);
+ }
+
+ if (x)
+ *x = sum_x;
+ if (y)
+ *y = sum_y;
+}
+
+static unsigned int
+_ecore_imf_modifier_to_ibus_modifier(unsigned int modifier)
+{
+ unsigned int state = 0;
+
+ /**< "Control" is pressed */
+ if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
+ state |= IBUS_CONTROL_MASK;
+
+ /**< "Alt" is pressed */
+ if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
+ state |= IBUS_MOD1_MASK;
+
+ /**< "Shift" is pressed */
+ if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
+ state |= IBUS_SHIFT_MASK;
+
+ /**< "Win" (between "Ctrl" and "Alt") */
+ if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
+ state |= IBUS_SUPER_MASK;
+
+ /**< "AltGr" is pressed */
+ if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
+ state |= IBUS_MOD5_MASK;
+
+ return state;
+}
+
+static void
+key_event_put(int keysym, int state)
+{
+ // Find the window which has the current keyboard focus.
+ Window winFocus = 0;
+ int revert = RevertToParent;
+
+ XGetInputFocus(ecore_x_display_get(), &winFocus, &revert);
+
+ XKeyEvent event;
+ if (state & IBUS_RELEASE_MASK)
+ {
+ event = createXKeyEvent(winFocus, EINA_FALSE, keysym, state);
+ XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
+ }
+ else
+ {
+ event = createXKeyEvent(winFocus, EINA_TRUE, keysym, state);
+ XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
+ }
+}
+
+static KeyEvent *
+key_event_copy(int keysym, int state)
+{
+ KeyEvent *kev = calloc(1, sizeof(KeyEvent));
+ kev->keysym = keysym;
+ kev->state = state;
+
+ return kev;
+}
+
+IBusIMContext *
+ibus_im_context_new(void)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+
+ IBusIMContext *context = calloc(1, sizeof(IBusIMContext));
+
+ /* init bus object */
+ if (_bus == NULL)
+ {
+ char *display_name = NULL;
+
+ if ((display_name = getenv("DISPLAY")))
+ ibus_set_display(display_name);
+ else
+ ibus_set_display(":0.0");
+
+ _bus = ibus_bus_new();
+ }
+
+ return context;
+}
+
+static void
+_process_key_event_done(GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IBusInputContext *context = (IBusInputContext *)object;
+ KeyEvent *event = (KeyEvent *)user_data;
+
+ GError *error = NULL;
+ Eina_Bool retval = ibus_input_context_process_key_event_async_finish(context,
+ res,
+ &error);
+
+ if (error != NULL)
+ {
+ g_warning("Process Key Event failed: %s.", error->message);
+ g_error_free(error);
+ }
+
+ if (retval == EINA_FALSE)
+ {
+ key_event_put(event->keysym, event->state);
+ }
+ free(event);
+}
+
+EAPI void
+ibus_im_context_add(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+
+ char *s = NULL;
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ ibusimcontext->client_window = 0;
+
+ // Init ibus status
+ ibusimcontext->enable = EINA_FALSE;
+
+ // Init preedit status
+ ibusimcontext->preedit_string = NULL;
+ ibusimcontext->preedit_attrs = NULL;
+ ibusimcontext->preedit_cursor_pos = 0;
+ ibusimcontext->preedit_visible = EINA_FALSE;
+
+ // Init cursor area
+ ibusimcontext->cursor_x = -1;
+ ibusimcontext->cursor_y = -1;
+ ibusimcontext->cursor_w = 0;
+ ibusimcontext->cursor_h = 0;
+
+ ibusimcontext->ibuscontext = NULL;
+ ibusimcontext->has_focus = EINA_FALSE;
+ ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
+ ibusimcontext->ctx = ctx;
+
+ s = getenv("IBUS_ENABLE_SYNC_MODE");
+ if (s)
+ _use_sync_mode = !!atoi(s);
+
+ if (ibus_bus_is_connected(_bus))
+ _create_input_context (ibusimcontext);
+
+ g_signal_connect(_bus, "connected", G_CALLBACK (_bus_connected_cb), ctx);
+}
+
+EAPI void
+ibus_im_context_del(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ g_signal_handlers_disconnect_by_func(_bus, G_CALLBACK(_bus_connected_cb), ctx);
+
+ if (ibusimcontext->ibuscontext)
+ ibus_proxy_destroy((IBusProxy *)ibusimcontext->ibuscontext);
+
+ // release preedit
+ if (ibusimcontext->preedit_string)
+ free(ibusimcontext->preedit_string);
+ if (_focus_im_context == ctx)
+ _focus_im_context = NULL;
+}
+
+EAPI Eina_Bool
+ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
+{
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ibusimcontext, EINA_FALSE);
+
+ if (type != ECORE_IMF_EVENT_KEY_UP && type != ECORE_IMF_EVENT_KEY_DOWN)
+ return EINA_FALSE;
+
+ EINA_LOG_DBG("%s", __FUNCTION__);
+
+ if (G_LIKELY(ibusimcontext->ibuscontext && ibusimcontext->has_focus))
+ {
+ /* If context does not have focus, ibus will process key event in sync mode.
+ * It is a workaround for increase search in treeview.
+ */
+ Eina_Bool retval = EINA_FALSE;
+ int keycode;
+ int keysym;
+ unsigned int state = 0;
+
+ if (type == ECORE_IMF_EVENT_KEY_UP)
+ {
+ Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
+ if (ev->timestamp == 0)
+ return EINA_FALSE;
+
+ keycode = ecore_x_keysym_keycode_get(ev->key);
+ keysym = XStringToKeysym(ev->key);
+ state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers) | IBUS_RELEASE_MASK;
+
+ if (_use_sync_mode)
+ {
+ retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
+ keysym,
+ keycode - 8,
+ state);
+ }
+ else
+ {
+ ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
+ keysym,
+ keycode - 8,
+ state,
+ -1,
+ NULL,
+ _process_key_event_done,
+ key_event_copy(keysym, state));
+ retval = EINA_TRUE;
+ }
+ }
+ else if (type == ECORE_IMF_EVENT_KEY_DOWN)
+ {
+ Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
+ if (ev->timestamp == 0)
+ return EINA_FALSE;
+
+ keycode = ecore_x_keysym_keycode_get(ev->key);
+ keysym = XStringToKeysym(ev->key);
+ state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers);
+ if (_use_sync_mode)
+ {
+ retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext,
+ keysym,
+ keycode - 8,
+ state);
+ }
+ else
+ {
+ ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext,
+ keysym,
+ keycode - 8,
+ state,
+ -1,
+ NULL,
+ _process_key_event_done,
+ key_event_copy(keysym, state));
+ retval = EINA_TRUE;
+ }
+ }
+ else
+ retval = EINA_FALSE;
+
+ if (retval)
+ return EINA_TRUE;
+ else
+ return EINA_FALSE;
+ }
+ else
+ return EINA_FALSE;
+}
+
+EAPI void
+ibus_im_context_focus_in(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("ctx : %p", ctx);
+
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->has_focus)
+ return;
+
+ if (_focus_im_context != NULL)
+ ecore_imf_context_focus_out(_focus_im_context);
+
+ ibusimcontext->has_focus = EINA_TRUE;
+ if (ibusimcontext->ibuscontext)
+ ibus_input_context_focus_in(ibusimcontext->ibuscontext);
+
+ if (_focus_im_context != ctx)
+ _focus_im_context = ctx;
+}
+
+EAPI void
+ibus_im_context_focus_out(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("ctx : %p", ctx);
+
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->has_focus == EINA_FALSE)
+ return;
+
+ if (_focus_im_context == ctx)
+ _focus_im_context = NULL;
+
+ ibusimcontext->has_focus = EINA_FALSE;
+ if (ibusimcontext->ibuscontext)
+ ibus_input_context_focus_out(ibusimcontext->ibuscontext);
+}
+
+EAPI void
+ibus_im_context_reset(Ecore_IMF_Context *ctx)
+{
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->ibuscontext)
+ ibus_input_context_reset(ibusimcontext->ibuscontext);
+}
+
+EAPI void
+ibus_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
+ char **str,
+ int *cursor_pos)
+{
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->enable && ibusimcontext->preedit_visible)
+ {
+ if (str)
+ *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
+
+ if (cursor_pos)
+ *cursor_pos = ibusimcontext->preedit_cursor_pos;
+ }
+ else
+ {
+ if (str)
+ *str = strdup("");
+
+ if (cursor_pos)
+ *cursor_pos = 0;
+ }
+ EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
+}
+
+EAPI void
+ibus_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
+ char **str,
+ Eina_List **attr EINA_UNUSED,
+ int *cursor_pos)
+{
+ IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->enable && ibusimcontext->preedit_visible)
+ {
+ if (str)
+ *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
+
+ if (cursor_pos)
+ *cursor_pos = ibusimcontext->preedit_cursor_pos;
+ }
+ else
+ {
+ if (str)
+ *str = strdup("");
+
+ if (cursor_pos)
+ *cursor_pos = 0;
+ }
+ EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
+}
+
+EAPI void
+ibus_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
+{
+ EINA_LOG_DBG("canvas : %p", window);
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (window != NULL)
+ ibusimcontext->client_window = (Ecore_X_Window)(Ecore_Window)window;
+}
+
+EAPI void
+ibus_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
+{
+ EINA_LOG_DBG("canvas : %p", canvas);
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (canvas != NULL)
+ ibusimcontext->client_canvas = canvas;
+}
+
+static void
+_set_cursor_location_internal(Ecore_IMF_Context *ctx)
+{
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ Ecore_Evas *ee;
+ int canvas_x, canvas_y;
+
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->ibuscontext == NULL)
+ return;
+
+ if (ibusimcontext->client_canvas)
+ {
+ ee = ecore_evas_ecore_evas_get(ibusimcontext->client_canvas);
+ if (!ee) return;
+
+ ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
+ }
+ else
+ {
+ if (ibusimcontext->client_window)
+ _window_to_screen_geometry_get(ibusimcontext->client_window, &canvas_x, &canvas_y);
+ else
+ return;
+ }
+
+ ibus_input_context_set_cursor_location(ibusimcontext->ibuscontext,
+ ibusimcontext->cursor_x + canvas_x,
+ ibusimcontext->cursor_y + canvas_y,
+ ibusimcontext->cursor_w,
+ ibusimcontext->cursor_h);
+}
+
+EAPI void
+ibus_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h)
+{
+ EINA_LOG_DBG("x : %d, y : %d, w, %d, h :%d", x, y, w, h);
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->cursor_x != x ||
+ ibusimcontext->cursor_y != y ||
+ ibusimcontext->cursor_w != w ||
+ ibusimcontext->cursor_h != h)
+ {
+ ibusimcontext->cursor_x = x;
+ ibusimcontext->cursor_y = y;
+ ibusimcontext->cursor_w = w;
+ ibusimcontext->cursor_h = h;
+
+ _set_cursor_location_internal(ctx);
+ }
+}
+
+EAPI void
+ibus_im_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit)
+{
+ EINA_LOG_DBG("preedit : %d", use_preedit);
+ IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->ibuscontext)
+ {
+ if (use_preedit)
+ ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT;
+ else
+ ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
+
+ ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
+ }
+}
+
+static void
+_bus_connected_cb(IBusBus *bus EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("ibus is connected");
+
+ if (ibusimcontext)
+ _create_input_context(ibusimcontext);
+}
+
+static void
+_ibus_context_commit_text_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusText *text,
+ IBusIMContext *ibusimcontext)
+{
+ if (!ibusimcontext || !text) return;
+ char *commit_str = text->text ? text->text : "";
+
+ EINA_LOG_DBG("commit string : %s", commit_str);
+
+ if (ibusimcontext->ctx)
+ {
+ ecore_imf_context_commit_event_add(ibusimcontext->ctx, text->text);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit_str);
+ }
+}
+
+static XKeyEvent createXKeyEvent(Window win, Eina_Bool press, int keysym, int modifiers)
+{
+ XKeyEvent event;
+ Display *display = ecore_x_display_get();
+
+ event.display = display;
+ event.window = win;
+ event.root = ecore_x_window_root_get(win);
+ event.subwindow = None;
+ event.time = 0;
+ event.x = 1;
+ event.y = 1;
+ event.x_root = 1;
+ event.y_root = 1;
+ event.same_screen = EINA_TRUE;
+ event.state = modifiers;
+ event.keycode = XKeysymToKeycode(display, keysym);
+ if (press)
+ event.type = KeyPress;
+ else
+ event.type = KeyRelease;
+ event.send_event = EINA_FALSE;
+ event.serial = 0;
+
+ return event;
+}
+
+static void
+_ibus_context_forward_key_event_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ guint keyval,
+ guint state,
+ IBusIMContext *ibusimcontext EINA_UNUSED)
+{
+ EINA_LOG_DBG("keyval : %d, state : %d", keyval, state);
+
+ key_event_put(keyval, state);
+}
+
+static void
+_ibus_context_update_preedit_text_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusText *text,
+ gint cursor_pos,
+ gboolean visible,
+ IBusIMContext *ibusimcontext)
+{
+ if (!ibusimcontext || !text) return;
+
+ const char *str;
+ gboolean flag;
+
+ if (ibusimcontext->preedit_string)
+ free (ibusimcontext->preedit_string);
+
+ str = text->text;
+
+ if (str)
+ ibusimcontext->preedit_string = strdup(str);
+ else
+ ibusimcontext->preedit_string = strdup("");
+
+ ibusimcontext->preedit_cursor_pos = cursor_pos;
+
+ EINA_LOG_DBG("string : %s, cursor : %d", ibusimcontext->preedit_string, ibusimcontext->preedit_cursor_pos);
+
+ flag = ibusimcontext->preedit_visible != visible;
+ ibusimcontext->preedit_visible = visible;
+
+ if (ibusimcontext->preedit_visible)
+ {
+ if (flag)
+ {
+ ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ }
+
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+ else
+ {
+ if (flag)
+ {
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+
+ ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+ }
+}
+
+static void
+_ibus_context_show_preedit_text_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("preedit visible : %d", ibusimcontext->preedit_visible);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->preedit_visible == EINA_TRUE)
+ return;
+
+ ibusimcontext->preedit_visible = EINA_TRUE;
+
+ // call preedit start
+ ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+
+ // call preedit changed
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+}
+
+static void
+_ibus_context_hide_preedit_text_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ if (ibusimcontext->preedit_visible == EINA_FALSE)
+ return;
+
+ ibusimcontext->preedit_visible = EINA_FALSE;
+
+ // call preedit changed
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+
+ // call preedit end
+ ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+}
+
+static void
+_ibus_context_enabled_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ ibusimcontext->enable = EINA_TRUE;
+}
+
+static void
+_ibus_context_disabled_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ ibusimcontext->enable = EINA_FALSE;
+
+ /* clear preedit */
+ ibusimcontext->preedit_visible = EINA_FALSE;
+ ibusimcontext->preedit_cursor_pos = 0;
+ free (ibusimcontext->preedit_string);
+ ibusimcontext->preedit_string = NULL;
+
+ // call preedit changed
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+
+ // call preedit end
+ ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+}
+
+static void
+_ibus_context_destroy_cb(IBusInputContext *ibuscontext EINA_UNUSED,
+ IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ ibusimcontext->ibuscontext = NULL;
+ ibusimcontext->enable = EINA_FALSE;
+
+ /* clear preedit */
+ ibusimcontext->preedit_visible = EINA_FALSE;
+ ibusimcontext->preedit_cursor_pos = 0;
+ free (ibusimcontext->preedit_string);
+ ibusimcontext->preedit_string = NULL;
+
+ // call preedit changed
+ ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+
+ // call preedit end
+ ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
+ ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+}
+
+static void
+_create_input_context(IBusIMContext *ibusimcontext)
+{
+ EINA_LOG_DBG("%s", __FUNCTION__);
+ EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
+
+ ibusimcontext->ibuscontext = ibus_bus_create_input_context(_bus, "ecore");
+
+ g_return_if_fail(ibusimcontext->ibuscontext != NULL);
+
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "commit-text",
+ G_CALLBACK (_ibus_context_commit_text_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "forward-key-event",
+ G_CALLBACK (_ibus_context_forward_key_event_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "update-preedit-text",
+ G_CALLBACK (_ibus_context_update_preedit_text_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "show-preedit-text",
+ G_CALLBACK (_ibus_context_show_preedit_text_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "hide-preedit-text",
+ G_CALLBACK (_ibus_context_hide_preedit_text_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "enabled",
+ G_CALLBACK (_ibus_context_enabled_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext,
+ "disabled",
+ G_CALLBACK (_ibus_context_disabled_cb),
+ ibusimcontext);
+ g_signal_connect(ibusimcontext->ibuscontext, "destroy",
+ G_CALLBACK (_ibus_context_destroy_cb),
+ ibusimcontext);
+
+ ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
+
+ if (ibusimcontext->has_focus)
+ ibus_input_context_focus_in(ibusimcontext->ibuscontext);
+}
diff --git a/src/modules/ecore/immodules/ibus/ibus_imcontext.h b/src/modules/ecore/immodules/ibus/ibus_imcontext.h
new file mode 100644
index 0000000000..ce5c075c3f
--- /dev/null
+++ b/src/modules/ecore/immodules/ibus/ibus_imcontext.h
@@ -0,0 +1,36 @@
+#ifndef __IBUS_IM_CONTEXT_H_
+#define __IBUS_IM_CONTEXT_H_
+
+#include <Ecore_IMF.h>
+
+typedef struct _IBusIMContext IBusIMContext;
+
+EAPI void ibus_im_context_add (Ecore_IMF_Context *ctx);
+EAPI void ibus_im_context_del (Ecore_IMF_Context *ctx);
+EAPI void ibus_im_context_reset (Ecore_IMF_Context *context);
+EAPI void ibus_im_context_focus_in(Ecore_IMF_Context *context);
+EAPI void ibus_im_context_focus_out(Ecore_IMF_Context *context);
+EAPI void ibus_im_context_preedit_string_get
+ (Ecore_IMF_Context *context,
+ char **str,
+ int *cursor_pos);
+EAPI void ibus_im_context_preedit_string_with_attributes_get
+ (Ecore_IMF_Context *context,
+ char **str,
+ Eina_List **attr,
+ int *cursor_pos);
+
+EAPI void ibus_im_context_cursor_location_set(Ecore_IMF_Context *context,
+ int x, int y, int w, int h);
+EAPI void ibus_im_context_use_preedit_set(Ecore_IMF_Context *context,
+ Eina_Bool use_preedit);
+EAPI void
+ibus_im_context_client_window_set(Ecore_IMF_Context *context, void *window);
+EAPI void
+ibus_im_context_client_canvas_set(Ecore_IMF_Context *context, void *canvas);
+EAPI Eina_Bool
+ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event);
+
+IBusIMContext
+ *ibus_im_context_new (void);
+#endif
diff --git a/src/modules/ecore/immodules/ibus/ibus_module.c b/src/modules/ecore/immodules/ibus/ibus_module.c
new file mode 100644
index 0000000000..a6e175c3ca
--- /dev/null
+++ b/src/modules/ecore/immodules/ibus/ibus_module.c
@@ -0,0 +1,109 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <Ecore.h>
+#include <Ecore_IMF.h>
+
+#include <ibus.h>
+#include "ibus_imcontext.h"
+
+#define IBUS_LOCALDIR ""
+static const Ecore_IMF_Context_Info ibus_im_info = {
+ "ibus",
+ "IBus (Intelligent Input Bus)",
+ "*",
+ NULL,
+ 0
+};
+
+static Ecore_IMF_Context_Class ibus_imf_class = {
+ ibus_im_context_add, /* add */
+ ibus_im_context_del, /* del */
+ ibus_im_context_client_window_set, /* client_window_set */
+ ibus_im_context_client_canvas_set, /* client_canvas_set */
+ NULL, /* input_panel_show */
+ NULL, /* input_panel_hide */
+ ibus_im_context_preedit_string_get, /* get_preedit_string */
+ ibus_im_context_focus_in, /* focus_in */
+ ibus_im_context_focus_out, /* focus_out */
+ ibus_im_context_reset, /* reset */
+ NULL, /* cursor_position_set */
+ ibus_im_context_use_preedit_set, /* use_preedit_set */
+ NULL, /* input_mode_set */
+ ibus_im_context_filter_event, /* filter_event */
+ ibus_im_context_preedit_string_with_attributes_get, /* preedit_string_with_attribute_get */
+ NULL, /* prediction_allow_set */
+ NULL, /* autocapital_type_set */
+ NULL, /* control panel show */
+ NULL, /* control panel hide */
+ NULL, /* input_panel_layout_set */
+ NULL, /* ibus_im_context_input_panel_layout_get, */
+ NULL, /* ibus_im_context_input_panel_language_set, */
+ NULL, /* ibus_im_context_input_panel_language_get, */
+ ibus_im_context_cursor_location_set, /* cursor_location_set */
+ NULL, /* input_panel_imdata_set */
+ NULL, /* input_panel_imdata_get */
+ NULL, /* input_panel_return_key_type_set */
+ NULL, /* input_panel_return_key_disabled_set */
+ NULL, /* input_panel_caps_lock_mode_set */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static Ecore_IMF_Context *im_module_create (void);
+static Ecore_IMF_Context *im_module_exit (void);
+
+static Eina_Bool
+im_module_init(void)
+{
+ ecore_main_loop_glib_integrate();
+ ibus_init();
+ ecore_imf_module_register(&ibus_im_info, im_module_create, im_module_exit);
+
+ return EINA_TRUE;
+}
+
+static void im_module_shutdown(void)
+{
+}
+
+static Ecore_IMF_Context *
+im_module_exit(void)
+{
+ return NULL;
+}
+
+static Ecore_IMF_Context *
+im_module_create()
+{
+ Ecore_IMF_Context *ctx = NULL;
+ IBusIMContext *ctxd = NULL;
+
+ ctxd = ibus_im_context_new();
+ if (!ctxd)
+ {
+ return NULL;
+ }
+
+ ctx = ecore_imf_context_new(&ibus_imf_class);
+ if (!ctx)
+ {
+ free(ctxd);
+ return NULL;
+ }
+
+ ecore_imf_context_data_set(ctx, ctxd);
+
+ return ctx;
+}
+
+EINA_MODULE_INIT(im_module_init);
+EINA_MODULE_SHUTDOWN(im_module_shutdown);
+
diff --git a/src/modules/ecore/immodules/scim/scim_imcontext.cpp b/src/modules/ecore/immodules/scim/scim_imcontext.cpp
new file mode 100644
index 0000000000..d4d20b161a
--- /dev/null
+++ b/src/modules/ecore/immodules/scim/scim_imcontext.cpp
@@ -0,0 +1,2900 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define Uses_SCIM_DEBUG
+#define Uses_SCIM_BACKEND
+#define Uses_SCIM_IMENGINE_MODULE
+#define Uses_SCIM_HOTKEY
+#define Uses_SCIM_PANEL_CLIENT
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <Ecore_Evas.h>
+#include <Ecore_X.h>
+#include <Ecore.h>
+#include <Evas.h>
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+
+#include <scim.h>
+#include "scim_imcontext.h"
+
+using namespace scim;
+
+struct _EcoreIMFContextISFImpl
+{
+ EcoreIMFContextISF *parent;
+ IMEngineInstancePointer si;
+ Ecore_X_Window client_window;
+ Evas *client_canvas;
+ Ecore_IMF_Input_Mode input_mode;
+ WideString preedit_string;
+ AttributeList preedit_attrlist;
+ Ecore_IMF_Autocapital_Type autocapital_type;
+ int preedit_caret;
+ int cursor_x;
+ int cursor_y;
+ int cursor_pos;
+ bool use_preedit;
+ bool is_on;
+ bool shared_si;
+ bool preedit_started;
+ bool preedit_updating;
+ bool need_commit_preedit;
+ bool uppercase;
+ bool prediction_allow;
+
+ EcoreIMFContextISFImpl *next;
+};
+
+/* Input Context handling functions. */
+static EcoreIMFContextISFImpl *new_ic_impl (EcoreIMFContextISF *parent);
+static void delete_ic_impl (EcoreIMFContextISFImpl *impl);
+static void delete_all_ic_impl (void);
+
+static EcoreIMFContextISF *find_ic (int id);
+
+
+/* private functions */
+static void panel_slot_reload_config (int context);
+static void panel_slot_exit (int context);
+static void panel_slot_update_lookup_table_page_size(int context,
+ int page_size);
+static void panel_slot_lookup_table_page_up (int context);
+static void panel_slot_lookup_table_page_down (int context);
+static void panel_slot_trigger_property (int context,
+ const String &property);
+static void panel_slot_process_helper_event (int context,
+ const String &target_uuid,
+ const String &helper_uuid,
+ const Transaction &trans);
+static void panel_slot_move_preedit_caret (int context,
+ int caret_pos);
+static void panel_slot_select_candidate (int context,
+ int cand_index);
+static void panel_slot_process_key_event (int context,
+ const KeyEvent &key);
+static void panel_slot_commit_string (int context,
+ const WideString &wstr);
+static void panel_slot_forward_key_event (int context,
+ const KeyEvent &key);
+static void panel_slot_request_help (int context);
+static void panel_slot_request_factory_menu (int context);
+static void panel_slot_change_factory (int context,
+ const String &uuid);
+
+static void panel_req_focus_in (EcoreIMFContextISF *ic);
+static void panel_req_update_factory_info (EcoreIMFContextISF *ic);
+static void panel_req_update_spot_location (EcoreIMFContextISF *ic);
+static void panel_req_show_help (EcoreIMFContextISF *ic);
+static void panel_req_show_factory_menu (EcoreIMFContextISF *ic);
+
+/* Panel iochannel handler*/
+static bool panel_initialize (void);
+static void panel_finalize (void);
+static Eina_Bool panel_iochannel_handler (void *data,
+ Ecore_Fd_Handler *fd_handler);
+
+/* utility functions */
+static bool filter_hotkeys (EcoreIMFContextISF *ic,
+ const KeyEvent &key);
+static void turn_on_ic (EcoreIMFContextISF *ic);
+static void turn_off_ic (EcoreIMFContextISF *ic);
+static void set_ic_capabilities (EcoreIMFContextISF *ic);
+
+static void initialize (void);
+static void finalize (void);
+
+static void open_next_factory (EcoreIMFContextISF *ic);
+static void open_previous_factory (EcoreIMFContextISF *ic);
+static void open_specific_factory (EcoreIMFContextISF *ic,
+ const String &uuid);
+static void initialize_modifier_bits (Display *display);
+static unsigned int scim_x11_keymask_scim_to_x11 (Display *display, uint16 scimkeymask);
+static XKeyEvent createKeyEvent (Display *display, Window &win,
+ Window &winRoot, bool press,
+ int keycode, int modifiers);
+static void _x_send_key_event (const KeyEvent &key);
+
+static void attach_instance (const IMEngineInstancePointer &si);
+
+/* slot functions */
+static void slot_show_preedit_string (IMEngineInstanceBase *si);
+static void slot_show_aux_string (IMEngineInstanceBase *si);
+static void slot_show_lookup_table (IMEngineInstanceBase *si);
+
+static void slot_hide_preedit_string (IMEngineInstanceBase *si);
+static void slot_hide_aux_string (IMEngineInstanceBase *si);
+static void slot_hide_lookup_table (IMEngineInstanceBase *si);
+
+static void slot_update_preedit_caret (IMEngineInstanceBase *si,
+ int caret);
+static void slot_update_preedit_string (IMEngineInstanceBase *si,
+ const WideString &str,
+ const AttributeList &attrs);
+static void slot_update_aux_string (IMEngineInstanceBase *si,
+ const WideString &str,
+ const AttributeList &attrs);
+static void slot_commit_string (IMEngineInstanceBase *si,
+ const WideString &str);
+static void slot_forward_key_event (IMEngineInstanceBase *si,
+ const KeyEvent &key);
+static void slot_update_lookup_table (IMEngineInstanceBase *si,
+ const LookupTable &table);
+
+static void slot_register_properties (IMEngineInstanceBase *si,
+ const PropertyList &properties);
+static void slot_update_property (IMEngineInstanceBase *si,
+ const Property &property);
+static void slot_beep (IMEngineInstanceBase *si);
+static void slot_start_helper (IMEngineInstanceBase *si,
+ const String &helper_uuid);
+static void slot_stop_helper (IMEngineInstanceBase *si,
+ const String &helper_uuid);
+static void slot_send_helper_event (IMEngineInstanceBase *si,
+ const String &helper_uuid,
+ const Transaction &trans);
+static bool slot_get_surrounding_text (IMEngineInstanceBase *si,
+ WideString &text,
+ int &cursor,
+ int maxlen_before,
+ int maxlen_after);
+static bool slot_delete_surrounding_text (IMEngineInstanceBase *si,
+ int offset,
+ int len);
+
+static void reload_config_callback (const ConfigPointer &config);
+
+static void fallback_commit_string_cb (IMEngineInstanceBase *si,
+ const WideString &str);
+
+static void caps_mode_check (Ecore_IMF_Context *ctx, Eina_Bool force);
+
+/* Local variables declaration */
+static String _language;
+static EcoreIMFContextISFImpl *_used_ic_impl_list = 0;
+static EcoreIMFContextISFImpl *_free_ic_impl_list = 0;
+static EcoreIMFContextISF *_ic_list = 0;
+
+static KeyboardLayout _keyboard_layout = SCIM_KEYBOARD_Default;
+static int _valid_key_mask = SCIM_KEY_AllMasks;
+
+static FrontEndHotkeyMatcher _frontend_hotkey_matcher;
+static IMEngineHotkeyMatcher _imengine_hotkey_matcher;
+
+static IMEngineInstancePointer _default_instance;
+
+static ConfigModule *_config_module = 0;
+static ConfigPointer _config;
+static BackEndPointer _backend;
+
+static EcoreIMFContextISF *_focused_ic = 0;
+
+static bool _scim_initialized = false;
+
+static int _instance_count = 0;
+static int _context_count = 0;
+
+static IMEngineFactoryPointer _fallback_factory;
+static IMEngineInstancePointer _fallback_instance;
+static PanelClient _panel_client;
+
+static Ecore_Fd_Handler *_panel_iochannel_read_handler = 0;
+static Ecore_Fd_Handler *_panel_iochannel_err_handler = 0;
+
+static Ecore_X_Window _client_window = 0;
+
+static bool _on_the_spot = true;
+static bool _shared_input_method = false;
+
+static Eina_Bool autocap_allow = EINA_FALSE;
+
+static Display *__current_display = 0;
+static int __current_alt_mask = Mod1Mask;
+static int __current_meta_mask = 0;
+static int __current_super_mask = 0;
+static int __current_hyper_mask = 0;
+static int __current_numlock_mask = Mod2Mask;
+
+// A hack to shutdown the immodule cleanly even if im_module_exit() is not called when exiting.
+class FinalizeHandler
+{
+public:
+ FinalizeHandler()
+ {
+ SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler()\n";
+ }
+ ~FinalizeHandler()
+ {
+ SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler()\n";
+ isf_imf_context_shutdown();
+ }
+};
+
+static FinalizeHandler _finalize_handler;
+
+static unsigned int
+utf8_offset_to_index(const char *str, int offset)
+{
+ int index = 0;
+ int i;
+ for (i = 0; i < offset; i++)
+ {
+ eina_unicode_utf8_get_next(str, &index);
+ }
+
+ return index;
+}
+
+static unsigned int
+get_time(void)
+{
+ unsigned int tint;
+ struct timeval tv;
+ struct timezone tz; /* is not used since ages */
+ gettimeofday(&tv, &tz);
+ tint = tv.tv_sec * 1000;
+ tint = tint / 1000 * 1000;
+ tint = tint + tv.tv_usec / 1000;
+ return tint;
+}
+
+/* Function Implementations */
+static EcoreIMFContextISFImpl *
+new_ic_impl(EcoreIMFContextISF *parent)
+{
+ EcoreIMFContextISFImpl *impl = NULL;
+
+ if (_free_ic_impl_list != NULL)
+ {
+ impl = _free_ic_impl_list;
+ _free_ic_impl_list = _free_ic_impl_list->next;
+ }
+ else
+ {
+ impl = new EcoreIMFContextISFImpl;
+ if (impl == NULL)
+ return NULL;
+ }
+
+ impl->uppercase = false;
+ impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
+ impl->next = _used_ic_impl_list;
+ _used_ic_impl_list = impl;
+
+ impl->parent = parent;
+
+ return impl;
+}
+
+static void
+delete_ic_impl(EcoreIMFContextISFImpl *impl)
+{
+ EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0;
+
+ for (; rec != 0; last = rec, rec = rec->next)
+ {
+ if (rec == impl)
+ {
+ if (last != 0)
+ last->next = rec->next;
+ else
+ _used_ic_impl_list = rec->next;
+
+ rec->next = _free_ic_impl_list;
+ _free_ic_impl_list = rec;
+
+ rec->parent = 0;
+ rec->si.reset();
+ rec->client_window = 0;
+ rec->preedit_string = WideString();
+ rec->preedit_attrlist.clear();
+
+ return;
+ }
+ }
+}
+
+static void
+delete_all_ic_impl(void)
+{
+ EcoreIMFContextISFImpl *it = _used_ic_impl_list;
+
+ while (it != 0)
+ {
+ _used_ic_impl_list = it->next;
+ delete it;
+ it = _used_ic_impl_list;
+ }
+
+ it = _free_ic_impl_list;
+ while (it != 0)
+ {
+ _free_ic_impl_list = it->next;
+ delete it;
+ it = _free_ic_impl_list;
+ }
+}
+
+static EcoreIMFContextISF *
+find_ic(int id)
+{
+ EcoreIMFContextISFImpl *rec = _used_ic_impl_list;
+
+ while (rec != 0)
+ {
+ if (rec->parent && rec->parent->id == id)
+ return rec->parent;
+ rec = rec->next;
+ }
+
+ return 0;
+}
+
+static Eina_Bool
+analyze_surrounding_text(Ecore_IMF_Context *ctx)
+{
+ char *plain_str = NULL;
+ char *markup_str = NULL;
+ const char *puncs[] = {". ", "! ", "? "};
+ Eina_Bool ret = EINA_FALSE;
+ int cursor_pos = 0;
+ int i = 0;
+ Eina_Unicode *tail = NULL;
+ Eina_Unicode *ustr = NULL;
+ const int punc_num = sizeof(puncs) / sizeof(puncs[0]);
+ Eina_Unicode *uni_puncs[punc_num];
+ EcoreIMFContextISF *context_scim;
+
+ if (!ctx) return EINA_FALSE;
+ context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+ if (!context_scim || !context_scim->impl) return EINA_FALSE;
+
+ switch (context_scim->impl->autocapital_type)
+ {
+ case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
+ return EINA_FALSE;
+ case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
+ return EINA_TRUE;
+ default:
+ break;
+ }
+
+ for (i = 0; i < punc_num; i++)
+ uni_puncs[i] = eina_unicode_utf8_to_unicode(puncs[i], NULL);
+
+ ecore_imf_context_surrounding_get(ctx, &markup_str, &cursor_pos);
+ if (!markup_str) goto done;
+
+ if (cursor_pos == 0)
+ {
+ ret = EINA_TRUE;
+ goto done;
+ }
+
+ // Convert into plain string
+ plain_str = evas_textblock_text_markup_to_utf8(NULL, markup_str);
+ if (!plain_str) goto done;
+
+ // Convert string from UTF-8 to unicode
+ ustr = eina_unicode_utf8_to_unicode(plain_str, NULL);
+ if (!ustr) goto done;
+
+ if (cursor_pos >= 1)
+ {
+ if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
+ {
+ if (ustr[cursor_pos-1] == ' ')
+ {
+ ret = EINA_TRUE;
+ goto done;
+ }
+ }
+
+ // Check paragraph separator <PS> and carriage return <br>
+ if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n'))
+ {
+ ret = EINA_TRUE;
+ goto done;
+ }
+ }
+
+ // check punctuation
+ if (cursor_pos >= 2)
+ {
+ tail = eina_unicode_strndup(ustr+cursor_pos-2, 2);
+
+ if (tail)
+ {
+ for (i = 0; i < punc_num; i++)
+ {
+ if (!eina_unicode_strcmp(tail, uni_puncs[i]))
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+ free(tail);
+ tail = NULL;
+ }
+ }
+
+done:
+ if (ustr) free(ustr);
+ if (markup_str) free(markup_str);
+ if (plain_str) free(plain_str);
+
+ for (i = 0; i < punc_num; i++)
+ if (uni_puncs[i]) free(uni_puncs[i]);
+
+ return ret;
+}
+
+static void
+caps_mode_check(Ecore_IMF_Context *ctx, Eina_Bool force)
+{
+ Eina_Bool uppercase;
+ EcoreIMFContextISF *context_scim;
+
+ if (!ctx) return;
+ context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (autocap_allow == EINA_FALSE)
+ return;
+
+ // Check autocapital type
+ if (!context_scim || !context_scim->impl)
+ return;
+
+ if (analyze_surrounding_text(ctx))
+ uppercase = EINA_TRUE;
+ else
+ uppercase = EINA_FALSE;
+
+ if (force)
+ context_scim->impl->uppercase = uppercase;
+ else
+ if (context_scim->impl->uppercase != uppercase)
+ context_scim->impl->uppercase = uppercase;
+}
+
+static void
+feed_key_event(Evas *evas, const char *str, Eina_Bool fake)
+{
+ char key_string[128] = {0};
+ unsigned int timestamp = 0;
+
+ if (!fake)
+ timestamp = get_time();
+
+ if (strncmp(str, "KeyRelease+", 11) == 0)
+ {
+ strncpy(key_string, str + 11, strlen(str)-11);
+ evas_event_feed_key_up(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
+ SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_up()...\n";
+ }
+ else
+ {
+ strncpy(key_string, str, strlen(str));
+ evas_event_feed_key_down(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
+ SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_down()...\n";
+ }
+}
+
+static void
+window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
+{
+ Ecore_X_Window root_window, win;
+ int win_x, win_y;
+ int sum_x = 0, sum_y = 0;
+
+ root_window = ecore_x_window_root_get(client_win);
+ win = client_win;
+
+ while (root_window != win)
+ {
+ ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
+ sum_x += win_x;
+ sum_y += win_y;
+ win = ecore_x_window_parent_get(win);
+ }
+
+ if (x)
+ *x = sum_x;
+ if (y)
+ *y = sum_y;
+}
+
+/* Public functions */
+/**
+ * isf_imf_context_new
+ *
+ * This function will be called by Ecore IMF.
+ * Create a instance of type EcoreIMFContextISF.
+ *
+ * Return value: A pointer to the newly created EcoreIMFContextISF instance
+ */
+EAPI EcoreIMFContextISF *
+isf_imf_context_new(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+ char *env;
+
+ EcoreIMFContextISF *context_scim = new EcoreIMFContextISF;
+ if (context_scim == NULL)
+ {
+ std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
+ return NULL;
+ }
+
+ context_scim->id = _context_count++;
+
+ if (!_scim_initialized)
+ {
+ initialize();
+ _scim_initialized = true;
+ }
+
+ env = getenv("ECORE_IMF_AUTOCAPITAL_ALLOW");
+ if (env)
+ autocap_allow = !!atoi(env);
+
+ return context_scim;
+}
+
+/**
+ * isf_imf_context_shutdown
+ *
+ * It will be called when the scim im module is unloaded by ecore. It will do some
+ * cleanup job.
+ */
+EAPI void
+isf_imf_context_shutdown(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (_scim_initialized)
+ {
+ _scim_initialized = false;
+ finalize();
+ }
+}
+
+EAPI void
+isf_imf_context_add(Ecore_IMF_Context *ctx)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+
+ if (!context_scim) return;
+
+ context_scim->impl = NULL;
+
+ if (_backend.null())
+ return;
+
+ IMEngineInstancePointer si;
+
+ // Use the default instance if "shared input method" mode is enabled.
+ if (_shared_input_method && !_default_instance.null())
+ {
+ si = _default_instance;
+ SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
+ }
+
+ // Not in "shared input method" mode, or no default instance, create an instance.
+ if (si.null())
+ {
+ IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
+ if (factory.null()) return;
+ si = factory->create_instance("UTF-8", _instance_count++);
+ if (si.null()) return;
+ attach_instance(si);
+ SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
+ }
+
+ // If "shared input method" mode is enabled, and there is no default instance,
+ // then store this instance as default one.
+ if (_shared_input_method && _default_instance.null())
+ {
+ SCIM_DEBUG_FRONTEND(2) << "update default instance.\n";
+ _default_instance = si;
+ }
+
+ context_scim->ctx = ctx;
+ context_scim->impl = new_ic_impl(context_scim);
+ if (context_scim->impl == NULL)
+ {
+ std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
+ return;
+ }
+
+ context_scim->impl->si = si;
+ context_scim->impl->client_window = 0;
+ context_scim->impl->client_canvas = NULL;
+ context_scim->impl->preedit_caret = 0;
+ context_scim->impl->cursor_x = 0;
+ context_scim->impl->cursor_y = 0;
+ context_scim->impl->cursor_pos = -1;
+ context_scim->impl->is_on = false;
+ context_scim->impl->shared_si = _shared_input_method;
+ context_scim->impl->use_preedit = _on_the_spot;
+ context_scim->impl->preedit_started = false;
+ context_scim->impl->preedit_updating = false;
+ context_scim->impl->need_commit_preedit = false;
+
+ if (!_ic_list)
+ context_scim->next = NULL;
+ else
+ context_scim->next = _ic_list;
+ _ic_list = context_scim;
+
+ if (_shared_input_method)
+ context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
+
+ _panel_client.prepare(context_scim->id);
+ _panel_client.register_input_context(context_scim->id, si->get_factory_uuid());
+ set_ic_capabilities(context_scim);
+ _panel_client.send();
+
+ SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n";
+}
+
+EAPI void
+isf_imf_context_del(Ecore_IMF_Context *ctx)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (!_ic_list) return;
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+
+ if (context_scim)
+ {
+ if (context_scim->id != _ic_list->id)
+ {
+ EcoreIMFContextISF * pre = _ic_list;
+ EcoreIMFContextISF * cur = _ic_list->next;
+ while (cur != NULL)
+ {
+ if (cur->id == context_scim->id)
+ {
+ pre->next = cur->next;
+ break;
+ }
+ pre = cur;
+ cur = cur->next;
+ }
+ }
+ else
+ _ic_list = _ic_list->next;
+ }
+
+ if (context_scim && context_scim->impl)
+ {
+ _panel_client.prepare(context_scim->id);
+
+ if (context_scim == _focused_ic)
+ context_scim->impl->si->focus_out();
+
+ // Delete the instance.
+ EcoreIMFContextISF *old_focused = _focused_ic;
+ _focused_ic = context_scim;
+ context_scim->impl->si.reset();
+ _focused_ic = old_focused;
+
+ if (context_scim == _focused_ic)
+ {
+ _panel_client.turn_off(context_scim->id);
+ _panel_client.focus_out(context_scim->id);
+ }
+
+ _panel_client.remove_input_context(context_scim->id);
+ _panel_client.send();
+
+ if (context_scim->impl->client_window)
+ isf_imf_context_client_window_set(ctx, NULL);
+
+ if (context_scim->impl)
+ {
+ delete_ic_impl(context_scim->impl);
+ context_scim->impl = 0;
+ }
+ }
+
+ if (context_scim == _focused_ic)
+ _focused_ic = 0;
+
+ if (context_scim)
+ {
+ delete context_scim;
+ context_scim = 0;
+ }
+}
+
+/**
+ * isf_imf_context_client_canvas_set
+ * @ctx: a #Ecore_IMF_Context
+ * @canvas: the client canvas
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Set the client canvas for the Input Method Context; this is the canvas
+ * in which the input appears.
+ *
+ * The canvas type can be determined by using the context canvas type.
+ * Actually only canvas with type "evas" (Evas *) is supported. This canvas
+ * may be used in order to correctly position status windows, and may also
+ * be used for purposes internal to the Input Method Context.
+ */
+EAPI void
+isf_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->client_canvas != (Evas*) canvas)
+ context_scim->impl->client_canvas = (Evas*)canvas;
+}
+
+/**
+ * isf_imf_context_client_window_set
+ * @ctx: a #Ecore_IMF_Context
+ * @window: the client window
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Set the client window for the Input Method Context; this is the Ecore_X_Window
+ * when using X11, Ecore_Win32_Window when using Win32, etc.
+ *
+ * This window is used in order to correctly position status windows,
+ * and may also be used for purposes internal to the Input Method Context.
+ */
+EAPI void
+isf_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window))
+ {
+ context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window);
+
+ if ((context_scim->impl->client_window != 0) &&
+ (context_scim->impl->client_window != _client_window))
+ _client_window = context_scim->impl->client_window;
+ }
+}
+
+/**
+ * isf_imf_context_reset
+ * @ctx: a #Ecore_IMF_Context
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Notify the Input Method Context that a change such as a change in cursor
+ * position has been made. This will typically cause the Input Method Context
+ * to clear the preedit state.
+ */
+EAPI void
+isf_imf_context_reset(Ecore_IMF_Context *ctx)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim == _focused_ic)
+ {
+ WideString wstr = context_scim->impl->preedit_string;
+
+ _panel_client.prepare(context_scim->id);
+ context_scim->impl->si->reset();
+ _panel_client.send();
+
+ if (context_scim->impl->need_commit_preedit)
+ {
+ if (wstr.length())
+ {
+ ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
+ ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
+ }
+ _panel_client.prepare(context_scim->id);
+ _panel_client.send();
+ }
+ }
+}
+
+/**
+ * isf_imf_context_focus_in
+ * @ctx: a #Ecore_IMF_Context
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Notify the Input Method Context that the widget to which its correspond has gained focus.
+ */
+EAPI void
+isf_imf_context_focus_in(Ecore_IMF_Context *ctx)
+{
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (!context_scim)
+ return;
+
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n";
+
+ if (_focused_ic)
+ {
+ if (_focused_ic == context_scim)
+ {
+ SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n";
+ return;
+ }
+ SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n";
+ if (_focused_ic->ctx)
+ isf_imf_context_focus_out(_focused_ic->ctx);
+ }
+
+ bool need_cap = false;
+ bool need_reset = false;
+ bool need_reg = false;
+
+ if (context_scim && context_scim->impl)
+ {
+ _focused_ic = context_scim;
+ _panel_client.prepare(context_scim->id);
+
+ // Handle the "Shared Input Method" mode.
+ if (_shared_input_method)
+ {
+ SCIM_DEBUG_FRONTEND(2) << "shared input method.\n";
+ IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
+ if (!factory.null())
+ {
+ if (_default_instance.null() || _default_instance->get_factory_uuid() != factory->get_uuid())
+ {
+ _default_instance = factory->create_instance("UTF-8", _default_instance.null() ? _instance_count++ : _default_instance->get_id());
+ attach_instance(_default_instance);
+ SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id() << " " << _default_instance->get_factory_uuid() << "\n";
+ }
+
+ context_scim->impl->shared_si = true;
+ context_scim->impl->si = _default_instance;
+
+ context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
+ context_scim->impl->preedit_string.clear();
+ context_scim->impl->preedit_attrlist.clear();
+ context_scim->impl->preedit_caret = 0;
+ context_scim->impl->preedit_started = false;
+ need_cap = true;
+ need_reset = true;
+ need_reg = true;
+ }
+ }
+ else if (context_scim->impl->shared_si)
+ {
+ SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n";
+ IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
+ if (!factory.null())
+ {
+ context_scim->impl->si = factory->create_instance("UTF-8", _instance_count++);
+ context_scim->impl->preedit_string.clear();
+ context_scim->impl->preedit_attrlist.clear();
+ context_scim->impl->preedit_caret = 0;
+ context_scim->impl->preedit_started = false;
+ attach_instance(context_scim->impl->si);
+ need_cap = true;
+ need_reg = true;
+ context_scim->impl->shared_si = false;
+ SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id() << " " << context_scim->impl->si->get_factory_uuid() << "\n";
+ }
+ }
+
+ context_scim->impl->si->set_frontend_data(static_cast <void*>(context_scim));
+
+ if (need_reg) _panel_client.register_input_context(context_scim->id, context_scim->impl->si->get_factory_uuid());
+ if (need_cap) set_ic_capabilities(context_scim);
+ if (need_reset) context_scim->impl->si->reset();
+
+ panel_req_focus_in(context_scim);
+ panel_req_update_spot_location(context_scim);
+ panel_req_update_factory_info(context_scim);
+
+ if (context_scim->impl->is_on)
+ {
+ _panel_client.turn_on(context_scim->id);
+ _panel_client.hide_preedit_string(context_scim->id);
+ _panel_client.hide_aux_string(context_scim->id);
+ _panel_client.hide_lookup_table(context_scim->id);
+ context_scim->impl->si->focus_in();
+ }
+ else
+ {
+ _panel_client.turn_off(context_scim->id);
+ }
+
+ _panel_client.send();
+ }
+
+ if (ecore_imf_context_input_panel_enabled_get(ctx))
+ ecore_imf_context_input_panel_show(ctx);
+}
+
+/**
+ * isf_imf_context_focus_out
+ * @ctx: a #Ecore_IMF_Context
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Notify the Input Method Context that the widget to which its correspond has lost focus.
+ */
+EAPI void
+isf_imf_context_focus_out(Ecore_IMF_Context *ctx)
+{
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (!context_scim) return;
+
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n";
+
+ if (context_scim && context_scim->impl && context_scim == _focused_ic)
+ {
+ WideString wstr = context_scim->impl->preedit_string;
+
+ if (context_scim->impl->need_commit_preedit)
+ {
+ if (wstr.length())
+ {
+ ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
+ ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
+ }
+ _panel_client.prepare(context_scim->id);
+ _panel_client.send();
+ }
+
+ _panel_client.prepare(context_scim->id);
+ context_scim->impl->si->focus_out();
+ context_scim->impl->si->reset();
+ _panel_client.turn_off(context_scim->id);
+ _panel_client.focus_out(context_scim->id);
+ _panel_client.send();
+ _focused_ic = 0;
+ }
+
+ if (ecore_imf_context_input_panel_enabled_get(ctx))
+ ecore_imf_context_input_panel_hide(ctx);
+}
+
+/**
+ * isf_imf_context_cursor_location_set
+ * @ctx: a #Ecore_IMF_Context
+ * @x: x position of New cursor.
+ * @y: y position of New cursor.
+ * @w: the width of New cursor.
+ * @h: the height of New cursor.
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Notify the Input Method Context that a change in the cursor location has been made.
+ */
+EAPI void
+isf_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+ Ecore_Evas *ee;
+ int canvas_x, canvas_y;
+ int new_cursor_x, new_cursor_y;
+
+ if (cw == 0 && ch == 0)
+ return;
+
+ if (context_scim && context_scim->impl && context_scim == _focused_ic)
+ {
+ if (context_scim->impl->client_canvas)
+ {
+ ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas);
+ if (!ee) return;
+
+ ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
+ }
+ else
+ {
+ if (context_scim->impl->client_window)
+ window_to_screen_geometry_get(context_scim->impl->client_window, &canvas_x, &canvas_y);
+ else
+ return;
+ }
+
+ new_cursor_x = canvas_x + cx;
+ new_cursor_y = canvas_y + cy + ch;
+
+ // Don't update spot location while updating preedit string.
+ if (context_scim->impl->preedit_updating && (context_scim->impl->cursor_y == new_cursor_y))
+ return;
+
+ if (context_scim->impl->cursor_x != new_cursor_x || context_scim->impl->cursor_y != new_cursor_y)
+ {
+ context_scim->impl->cursor_x = new_cursor_x;
+ context_scim->impl->cursor_y = new_cursor_y;
+ _panel_client.prepare(context_scim->id);
+ panel_req_update_spot_location(context_scim);
+ _panel_client.send();
+ SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n";
+ }
+ }
+}
+
+/**
+ * isf_imf_context_use_preedit_set
+ * @ctx: a #Ecore_IMF_Context
+ * @use_preedit: Whether the IM context should use the preedit string.
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Set whether the IM context should use the preedit string to display feedback.
+ * If is 0 (default is 1), then the IM context may use some other method to
+ * display feedback, such as displaying it in a child of the root window.
+ */
+EAPI void
+isf_imf_context_use_preedit_set(Ecore_IMF_Context* ctx, Eina_Bool use_preedit)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (use_preedit ? "true" : "false") << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+
+ if (!_on_the_spot) return;
+
+ if (context_scim && context_scim->impl)
+ {
+ bool old = context_scim->impl->use_preedit;
+ context_scim->impl->use_preedit = use_preedit;
+ if (context_scim == _focused_ic)
+ {
+ _panel_client.prepare(context_scim->id);
+
+ if (old != use_preedit)
+ set_ic_capabilities(context_scim);
+
+ if (context_scim->impl->preedit_string.length())
+ slot_show_preedit_string(context_scim->impl->si);
+
+ _panel_client.send();
+ }
+ }
+}
+
+EAPI void
+isf_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->is_on)
+ {
+ String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
+
+ if (str)
+ {
+ if (mbs.length())
+ *str = strdup(mbs.c_str());
+ else
+ *str = strdup("");
+ }
+
+ if (cursor_pos)
+ {
+ *cursor_pos = context_scim->impl->preedit_caret;
+ }
+
+ if (attrs)
+ {
+ if (mbs.length())
+ {
+ int start_index, end_index;
+ int wlen = context_scim->impl->preedit_string.length();
+
+ Ecore_IMF_Preedit_Attr *attr = NULL;
+ AttributeList::const_iterator i;
+ bool *attrs_flag = new bool [mbs.length()];
+ memset(attrs_flag, 0, mbs.length() *sizeof(bool));
+
+ for (i = context_scim->impl->preedit_attrlist.begin();
+ i != context_scim->impl->preedit_attrlist.end(); ++i)
+ {
+ start_index = i->get_start();
+ end_index = i->get_end();
+
+ if (end_index <= wlen && start_index < end_index && i->get_type() != SCIM_ATTR_DECORATE_NONE)
+ {
+ start_index = utf8_offset_to_index(mbs.c_str(), i->get_start());
+ end_index = utf8_offset_to_index(mbs.c_str(), i->get_end());
+
+ if (i->get_type() == SCIM_ATTR_DECORATE)
+ {
+ attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
+ if (attr == NULL)
+ continue;
+ attr->start_index = start_index;
+ attr->end_index = end_index;
+
+ if (i->get_value() == SCIM_ATTR_DECORATE_UNDERLINE)
+ {
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
+ *attrs = eina_list_append(*attrs, (void *)attr);
+ }
+ else if (i->get_value() == SCIM_ATTR_DECORATE_REVERSE)
+ {
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
+ *attrs = eina_list_append(*attrs, (void *)attr);
+ }
+ else if (i->get_value() == SCIM_ATTR_DECORATE_HIGHLIGHT)
+ {
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
+ *attrs = eina_list_append(*attrs, (void *)attr);
+ }
+ else
+ {
+ free(attr);
+ }
+
+ switch(i->get_value())
+ {
+ case SCIM_ATTR_DECORATE_UNDERLINE:
+ case SCIM_ATTR_DECORATE_REVERSE:
+ case SCIM_ATTR_DECORATE_HIGHLIGHT:
+ // Record which character has attribute.
+ for (int pos = start_index; pos < end_index; ++pos)
+ attrs_flag [pos] = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (i->get_type() == SCIM_ATTR_FOREGROUND)
+ {
+ SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n";
+ }
+ else if (i->get_type() == SCIM_ATTR_BACKGROUND)
+ {
+ SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n";
+ }
+ }
+ }
+
+ // Add underline for all characters which don't have attribute.
+ for (unsigned int pos = 0; pos < mbs.length(); ++pos)
+ {
+ if (!attrs_flag [pos])
+ {
+ int begin_pos = pos;
+
+ while (pos < mbs.length() && !attrs_flag[pos])
+ ++pos;
+
+ // use REVERSE style as default
+ attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
+ if (attr == NULL)
+ continue;
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
+ attr->start_index = begin_pos;
+ attr->end_index = pos;
+ *attrs = eina_list_append(*attrs, (void *)attr);
+ }
+ }
+
+ delete [] attrs_flag;
+ }
+ }
+ }
+ else
+ {
+ if (str)
+ *str = strdup("");
+
+ if (cursor_pos)
+ *cursor_pos = 0;
+
+ if (attrs)
+ *attrs = NULL;
+ }
+}
+
+/**
+ * isf_imf_context_preedit_string_get
+ * @ctx: a #Ecore_IMF_Context
+ * @str: the preedit string
+ * @cursor_pos: the cursor position
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * To get the preedit string of the input method.
+ */
+EAPI void
+isf_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char** str, int *cursor_pos)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->is_on)
+ {
+ String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
+
+ if (str)
+ {
+ if (mbs.length())
+ *str = strdup(mbs.c_str());
+ else
+ *str = strdup("");
+ }
+
+ if (cursor_pos)
+ *cursor_pos = context_scim->impl->preedit_caret;
+ }
+ else
+ {
+ if (str)
+ *str = strdup("");
+
+ if (cursor_pos)
+ *cursor_pos = 0;
+ }
+}
+
+/**
+ * isf_imf_context_cursor_position_set
+ * @ctx: a #Ecore_IMF_Context
+ * @cursor_pos: New cursor position in characters.
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Notify the Input Method Context that a change in the cursor position has been made.
+ */
+EAPI void
+isf_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim == _focused_ic)
+ {
+ // Don't update spot location while updating preedit string.
+ if (context_scim->impl->preedit_updating)
+ return;
+
+ if (context_scim->impl->cursor_pos != cursor_pos)
+ {
+ context_scim->impl->cursor_pos = cursor_pos;
+ caps_mode_check(ctx, EINA_FALSE);
+ }
+ }
+}
+
+/**
+ * isf_imf_context_input_mode_set
+ * @ctx: a #Ecore_IMF_Context
+ * @input_mode: the input mode
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode
+ * is in Ecore_IMF.h.
+ */
+EAPI void
+isf_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+ if (context_scim && context_scim->impl)
+ context_scim->impl->input_mode = input_mode;
+}
+
+/**
+ * isf_imf_context_prediction_allow_set
+ * @ctx: a #Ecore_IMF_Context
+ * @use_prediction: Whether the IM context should use the prediction.
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Set whether the IM context should use the prediction.
+ */
+EAPI void
+isf_imf_context_prediction_allow_set(Ecore_IMF_Context* ctx, Eina_Bool prediction)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction ? "true" : "false") << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction)
+ context_scim->impl->prediction_allow = prediction;
+}
+
+EAPI void
+isf_imf_context_autocapital_type_set(Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << autocapital_type << "...\n";
+
+ EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
+
+ if (context_scim && context_scim->impl && context_scim->impl->autocapital_type != autocapital_type)
+ context_scim->impl->autocapital_type = autocapital_type;
+}
+
+/**
+ * isf_imf_context_filter_event
+ * @ctx: a #Ecore_IMF_Context
+ * @type: The type of event defined by Ecore_IMF_Event_Type.
+ * @event: The event itself.
+ * Return value: %TRUE if the input method handled the key event.
+ *
+ * This function will be called by Ecore IMF.
+ *
+ * Allow an Ecore Input Context to internally handle an event. If this function
+ * returns 1, then no further processing should be done for this event. Input
+ * methods must be able to accept all types of events (simply returning 0 if
+ * the event was not handled), but there is no obligation of any events to be
+ * submitted to this function.
+ */
+EAPI Eina_Bool
+isf_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+ Eina_Bool ret = EINA_FALSE;
+
+ if (ic == NULL || ic->impl == NULL)
+ return ret;
+
+ KeyEvent key;
+
+ if (type == ECORE_IMF_EVENT_KEY_DOWN)
+ {
+ Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
+ scim_string_to_key(key, ev->key);
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
+ if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
+ if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
+ }
+ else if (type == ECORE_IMF_EVENT_KEY_UP)
+ {
+ Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
+ scim_string_to_key(key, ev->key);
+ key.mask = SCIM_KEY_ReleaseMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
+ if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
+ if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
+ if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
+ }
+ else
+ {
+ return ret;
+ }
+
+ key.mask &= _valid_key_mask;
+
+ _panel_client.prepare(ic->id);
+
+ ret = EINA_TRUE;
+ if (!filter_hotkeys(ic, key))
+ {
+ if (!_focused_ic || !_focused_ic->impl->is_on ||
+ !_focused_ic->impl->si->process_key_event(key))
+ ret = EINA_FALSE;
+ }
+
+ _panel_client.send();
+
+ return ret;
+}
+
+EAPI void
+isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+ if (ic == NULL || ic->impl == NULL)
+ return;
+
+ ecore_x_e_virtual_keyboard_state_set
+ (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
+}
+
+EAPI void
+isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
+ if (ic == NULL || ic->impl == NULL)
+ return;
+
+ ecore_x_e_virtual_keyboard_state_set
+ (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
+}
+
+/* Panel Slot functions */
+static void
+panel_slot_reload_config(int context __UNUSED__)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+ _config->reload();
+}
+
+static void
+panel_slot_exit(int /* context */)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ finalize();
+}
+
+static void
+panel_slot_update_lookup_table_page_size(int context, int page_size)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->update_lookup_table_page_size(page_size);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_lookup_table_page_up(int context)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->lookup_table_page_up();
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_lookup_table_page_down(int context)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->lookup_table_page_down();
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_trigger_property(int context, const String &property)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->trigger_property(property);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid
+ << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid="
+ << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid() : "" ) << "\n";
+ if (ic && ic->impl && ic->impl->si->get_factory_uuid() == target_uuid)
+ {
+ _panel_client.prepare(ic->id);
+ SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
+ ic->impl->si->process_helper_event(helper_uuid, trans);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_move_preedit_caret(int context, int caret_pos)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->move_preedit_caret(caret_pos);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_select_candidate(int context, int cand_index)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ ic->impl->si->select_candidate(cand_index);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_process_key_event(int context, const KeyEvent &key)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
+
+ if (key.is_key_press())
+ ecore_x_test_fake_key_press(key.get_key_string().c_str());
+}
+
+static void
+panel_slot_commit_string(int context, const WideString &wstr)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n";
+
+ if (ic && ic->impl)
+ {
+ if (_focused_ic != ic)
+ return;
+
+ ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(wstr).c_str());
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
+ }
+}
+
+static void
+panel_slot_forward_key_event(int context, const KeyEvent &key)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
+
+ if (ic && ic->impl && ic->impl->client_canvas)
+ feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE);
+}
+
+static void
+panel_slot_request_help(int context)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
+
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ panel_req_show_help(ic);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_request_factory_menu(int context)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
+
+ if (ic && ic->impl)
+ {
+ _panel_client.prepare(ic->id);
+ panel_req_show_factory_menu(ic);
+ _panel_client.send();
+ }
+}
+
+static void
+panel_slot_change_factory(int context, const String &uuid)
+{
+ EcoreIMFContextISF *ic = find_ic(context);
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
+
+ if (ic && ic->impl)
+ {
+ ic->impl->si->reset();
+ _panel_client.prepare(ic->id);
+ open_specific_factory(ic, uuid);
+ _panel_client.send();
+ }
+}
+
+/* Panel Requestion functions. */
+static void
+panel_req_show_help(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ String help;
+
+ help = String("Smart Common Input Method platform ") +
+ //String(SCIM_VERSION) +
+ String("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
+
+ if (ic && ic->impl)
+ {
+ IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
+ if (sf)
+ {
+ help += utf8_wcstombs(sf->get_name());
+ help += String(":\n\n");
+
+ help += utf8_wcstombs(sf->get_help());
+ help += String("\n\n");
+
+ help += utf8_wcstombs(sf->get_credits());
+ }
+ _panel_client.show_help(ic->id, help);
+ }
+}
+
+static void
+panel_req_show_factory_menu(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ std::vector<IMEngineFactoryPointer> factories;
+ std::vector <PanelFactoryInfo> menu;
+
+ _backend->get_factories_for_encoding(factories, "UTF-8");
+
+ for (size_t i = 0; i < factories.size(); ++ i)
+ {
+ menu.push_back(PanelFactoryInfo(
+ factories [i]->get_uuid(),
+ utf8_wcstombs(factories [i]->get_name()),
+ factories [i]->get_language(),
+ factories [i]->get_icon_file()));
+ }
+
+ if (menu.size())
+ _panel_client.show_factory_menu(ic->id, menu);
+}
+
+static void
+panel_req_update_factory_info(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (ic && ic->impl && ic == _focused_ic)
+ {
+ PanelFactoryInfo info;
+ if (ic->impl->is_on)
+ {
+ IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
+ if (sf)
+ info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file());
+ }
+ else
+ {
+ info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), "");
+ }
+ _panel_client.update_factory_info(ic->id, info);
+ }
+}
+
+static void
+panel_req_focus_in(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid());
+}
+
+static void
+panel_req_update_spot_location(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
+}
+
+static bool
+filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ bool ret = false;
+
+ _frontend_hotkey_matcher.push_key_event(key);
+ _imengine_hotkey_matcher.push_key_event(key);
+
+ FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result();
+
+ if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
+ {
+ if (!ic->impl->is_on)
+ turn_on_ic(ic);
+ else
+ turn_off_ic(ic);
+ ret = true;
+ }
+ else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
+ {
+ if (!ic->impl->is_on)
+ turn_on_ic(ic);
+ ret = true;
+ }
+ else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
+ {
+ if (ic->impl->is_on)
+ turn_off_ic(ic);
+ ret = true;
+ }
+ else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
+ {
+ open_next_factory(ic);
+ ret = true;
+ }
+ else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
+ {
+ open_previous_factory(ic);
+ ret = true;
+ }
+ else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
+ {
+ panel_req_show_factory_menu(ic);
+ ret = true;
+ }
+ else if (_imengine_hotkey_matcher.is_matched())
+ {
+ String sfid = _imengine_hotkey_matcher.get_match_result();
+ open_specific_factory(ic, sfid);
+ ret = true;
+ }
+ return ret;
+}
+
+static bool
+panel_initialize(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ String display_name;
+ {
+ const char *p = getenv("DISPLAY");
+ if (p) display_name = String(p);
+ }
+
+ if (_panel_client.open_connection(_config->get_name(), display_name) >= 0)
+ {
+ int fd = _panel_client.get_connection_number();
+
+ _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
+
+ SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
+
+ return true;
+ }
+ std::cerr << "panel_initialize() failed!!!\n";
+ return false;
+}
+
+static void
+panel_finalize(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ _panel_client.close_connection();
+
+ if (_panel_iochannel_read_handler)
+ {
+ ecore_main_fd_handler_del(_panel_iochannel_read_handler);
+ _panel_iochannel_read_handler = 0;
+ }
+
+ if (_panel_iochannel_err_handler)
+ {
+ ecore_main_fd_handler_del(_panel_iochannel_err_handler);
+ _panel_iochannel_err_handler = 0;
+ }
+}
+
+static Eina_Bool
+panel_iochannel_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (fd_handler == _panel_iochannel_read_handler)
+ {
+ if (!_panel_client.filter_event())
+ {
+ panel_finalize();
+ panel_initialize();
+ return ECORE_CALLBACK_CANCEL;
+ }
+ }
+ else if (fd_handler == _panel_iochannel_err_handler)
+ {
+ panel_finalize();
+ panel_initialize();
+ return ECORE_CALLBACK_CANCEL;
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+turn_on_ic(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (ic && ic->impl && !ic->impl->is_on)
+ {
+ ic->impl->is_on = true;
+
+ if (ic == _focused_ic)
+ {
+ panel_req_focus_in(ic);
+ panel_req_update_spot_location(ic);
+ panel_req_update_factory_info(ic);
+ _panel_client.turn_on(ic->id);
+ _panel_client.hide_preedit_string(ic->id);
+ _panel_client.hide_aux_string(ic->id);
+ _panel_client.hide_lookup_table(ic->id);
+ ic->impl->si->focus_in();
+ }
+
+ //Record the IC on/off status
+ if (_shared_input_method)
+ _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
+
+ if (ic->impl->use_preedit && ic->impl->preedit_string.length())
+ {
+ ecore_imf_context_preedit_start_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ ic->impl->preedit_started = true;
+ }
+ }
+}
+
+static void
+turn_off_ic(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (ic && ic->impl && ic->impl->is_on)
+ {
+ ic->impl->is_on = false;
+
+ if (ic == _focused_ic)
+ {
+ ic->impl->si->focus_out();
+
+ panel_req_update_factory_info(ic);
+ _panel_client.turn_off(ic->id);
+ }
+
+ //Record the IC on/off status
+ if (_shared_input_method)
+ _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
+
+ if (ic->impl->use_preedit && ic->impl->preedit_string.length())
+ {
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ ecore_imf_context_preedit_end_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+ ic->impl->preedit_started = false;
+ }
+ }
+}
+
+static void
+set_ic_capabilities(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (ic && ic->impl)
+ {
+ unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
+
+ if (!_on_the_spot || !ic->impl->use_preedit)
+ cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
+
+ ic->impl->si->update_client_capabilities(cap);
+ }
+}
+
+static bool
+check_socket_frontend(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ SocketAddress address;
+ SocketClient client;
+
+ uint32 magic;
+
+ address.set_address(scim_get_default_socket_frontend_address());
+
+ if (!client.connect(address))
+ return false;
+
+ if (!scim_socket_open_connection(magic,
+ String("ConnectionTester"),
+ String("SocketFrontEnd"),
+ client,
+ 1000))
+ return false;
+
+ return true;
+}
+
+void
+initialize(void)
+{
+ std::vector<String> config_list;
+ std::vector<String> engine_list;
+ std::vector<String> load_engine_list;
+
+ std::vector<String>::iterator it;
+
+ bool manual = false;
+
+ bool socket = true;
+
+ String config_module_name = "simple";
+
+ printf("Initializing Ecore SCIM IMModule...\n");
+
+ SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
+
+ // Get system language.
+ _language = scim_get_locale_language(scim_get_current_locale());
+
+ if (socket)
+ {
+ // If no Socket FrontEnd is running, then launch one.
+ // And set manual to false.
+ bool check_result = check_socket_frontend();
+ if (!check_result)
+ {
+ std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
+ //get modules list
+ scim_get_imengine_module_list(engine_list);
+
+ for (it = engine_list.begin(); it != engine_list.end(); it++)
+ {
+ if (*it != "socket")
+ load_engine_list.push_back(*it);
+ }
+
+ const char *new_argv [] = { "--no-stay", 0 };
+ scim_launch(true,
+ config_module_name,
+ (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"),
+ "socket",
+ (char **)new_argv);
+ manual = false;
+ }
+
+ // If there is one Socket FrontEnd running and it's not manual mode,
+ // then just use this Socket Frontend.
+ if (!manual)
+ {
+ for (int i = 0; i < 200; ++i)
+ {
+ if (check_result)
+ {
+ config_module_name = "socket";
+ load_engine_list.clear();
+ load_engine_list.push_back("socket");
+ break;
+ }
+ scim_usleep(50000);
+ check_result = check_socket_frontend();
+ }
+ }
+ }
+
+ if (config_module_name != "dummy")
+ {
+ //load config module
+ SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
+ _config_module = new ConfigModule(config_module_name);
+
+ //create config instance
+ if (_config_module != NULL && _config_module->valid())
+ _config = _config_module->create_config();
+ }
+
+ if (_config.null())
+ {
+ SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
+
+ if (_config_module) delete _config_module;
+ _config_module = NULL;
+
+ _config = new DummyConfig();
+ config_module_name = "dummy";
+ }
+
+ reload_config_callback(_config);
+ _config->signal_connect_reload(slot(reload_config_callback));
+
+ // create backend
+ _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list);
+
+ if (_backend.null())
+ std::cerr << "Cannot create BackEnd Object!\n";
+ else
+ _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID);
+
+ if (_fallback_factory.null())
+ _fallback_factory = new DummyIMEngineFactory();
+
+ _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0);
+ _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb));
+
+ // Attach Panel Client signal.
+ _panel_client.signal_connect_reload_config (slot(panel_slot_reload_config));
+ _panel_client.signal_connect_exit (slot(panel_slot_exit));
+ _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size));
+ _panel_client.signal_connect_lookup_table_page_up (slot(panel_slot_lookup_table_page_up));
+ _panel_client.signal_connect_lookup_table_page_down (slot(panel_slot_lookup_table_page_down));
+ _panel_client.signal_connect_trigger_property (slot(panel_slot_trigger_property));
+ _panel_client.signal_connect_process_helper_event (slot(panel_slot_process_helper_event));
+ _panel_client.signal_connect_move_preedit_caret (slot(panel_slot_move_preedit_caret));
+ _panel_client.signal_connect_select_candidate (slot(panel_slot_select_candidate));
+ _panel_client.signal_connect_process_key_event (slot(panel_slot_process_key_event));
+ _panel_client.signal_connect_commit_string (slot(panel_slot_commit_string));
+ _panel_client.signal_connect_forward_key_event (slot(panel_slot_forward_key_event));
+ _panel_client.signal_connect_request_help (slot(panel_slot_request_help));
+ _panel_client.signal_connect_request_factory_menu (slot(panel_slot_request_factory_menu));
+ _panel_client.signal_connect_change_factory (slot(panel_slot_change_factory));
+
+ if (!panel_initialize())
+ std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
+}
+
+static void
+finalize(void)
+{
+ SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
+
+ // Reset this first so that the shared instance could be released correctly afterwards.
+ _default_instance.reset();
+
+ SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
+ while (_used_ic_impl_list)
+ {
+ // In case in "shared input method" mode,
+ // all contexts share only one instance,
+ // so we need point the reference pointer correctly before finalizing.
+ _used_ic_impl_list->si->set_frontend_data(static_cast <void*>(_used_ic_impl_list->parent));
+ isf_imf_context_del(_used_ic_impl_list->parent->ctx);
+ }
+
+ delete_all_ic_impl();
+
+ _fallback_instance.reset();
+ _fallback_factory.reset();
+
+ SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
+ _backend.reset();
+
+ SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
+ _config.reset();
+
+ if (_config_module)
+ {
+ SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
+ delete _config_module;
+ _config_module = 0;
+ }
+
+ _focused_ic = NULL;
+ _ic_list = NULL;
+
+ _scim_initialized = false;
+
+ panel_finalize();
+}
+
+static void
+open_next_factory(EcoreIMFContextISF *ic)
+{
+ SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
+ IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
+
+ if (!sf.null())
+ {
+ turn_off_ic(ic);
+ ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
+ ic->impl->si->set_frontend_data(static_cast <void*>(ic));
+ ic->impl->preedit_string = WideString();
+ ic->impl->preedit_caret = 0;
+ attach_instance(ic->impl->si);
+ _backend->set_default_factory(_language, sf->get_uuid());
+ _panel_client.register_input_context(ic->id, sf->get_uuid());
+ set_ic_capabilities(ic);
+ turn_on_ic(ic);
+
+ if (_shared_input_method)
+ {
+ _default_instance = ic->impl->si;
+ ic->impl->shared_si = true;
+ }
+ }
+}
+
+static void
+open_previous_factory(EcoreIMFContextISF *ic)
+{
+ if (ic == NULL)
+ return;
+
+ SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
+ IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
+
+ if (!sf.null())
+ {
+ turn_off_ic(ic);
+ ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
+ ic->impl->si->set_frontend_data(static_cast <void*>(ic));
+ ic->impl->preedit_string = WideString();
+ ic->impl->preedit_caret = 0;
+ attach_instance(ic->impl->si);
+ _backend->set_default_factory(_language, sf->get_uuid());
+ _panel_client.register_input_context(ic->id, sf->get_uuid());
+ set_ic_capabilities(ic);
+ turn_on_ic(ic);
+
+ if (_shared_input_method)
+ {
+ _default_instance = ic->impl->si;
+ ic->impl->shared_si = true;
+ }
+ }
+}
+
+static void
+open_specific_factory(EcoreIMFContextISF *ic,
+ const String &uuid)
+{
+ if (ic == NULL)
+ return;
+
+ SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
+
+ // The same input method is selected, just turn on the IC.
+ if (ic->impl->si->get_factory_uuid() == uuid)
+ {
+ turn_on_ic(ic);
+ return;
+ }
+
+ IMEngineFactoryPointer sf = _backend->get_factory(uuid);
+
+ if (uuid.length() && !sf.null())
+ {
+ turn_off_ic(ic);
+ ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
+ ic->impl->si->set_frontend_data(static_cast <void*>(ic));
+ ic->impl->preedit_string = WideString();
+ ic->impl->preedit_caret = 0;
+ attach_instance(ic->impl->si);
+ _backend->set_default_factory(_language, sf->get_uuid());
+ _panel_client.register_input_context(ic->id, sf->get_uuid());
+ set_ic_capabilities(ic);
+ turn_on_ic(ic);
+
+ if (_shared_input_method)
+ {
+ _default_instance = ic->impl->si;
+ ic->impl->shared_si = true;
+ }
+ }
+ else
+ {
+ // turn_off_ic comment out panel_req_update_factory_info()
+ turn_off_ic(ic);
+ if (ic && ic->impl->is_on)
+ {
+ ic->impl->is_on = false;
+
+ if (ic == _focused_ic)
+ {
+ ic->impl->si->focus_out();
+
+ panel_req_update_factory_info(ic);
+ _panel_client.turn_off(ic->id);
+ }
+
+ //Record the IC on/off status
+ if (_shared_input_method)
+ _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
+
+ if (ic->impl->use_preedit && ic->impl->preedit_string.length())
+ {
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ ecore_imf_context_preedit_end_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+ ic->impl->preedit_started = false;
+ }
+ }
+ }
+}
+
+static void initialize_modifier_bits(Display *display)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (__current_display == display)
+ return;
+
+ __current_display = display;
+
+ if (display == 0)
+ {
+ __current_alt_mask = Mod1Mask;
+ __current_meta_mask = ShiftMask | Mod1Mask;
+ __current_super_mask = 0;
+ __current_hyper_mask = 0;
+ __current_numlock_mask = Mod2Mask;
+ return;
+ }
+
+ XModifierKeymap *mods = NULL;
+
+ ::KeyCode ctrl_l = XKeysymToKeycode(display, XK_Control_L);
+ ::KeyCode ctrl_r = XKeysymToKeycode(display, XK_Control_R);
+ ::KeyCode meta_l = XKeysymToKeycode(display, XK_Meta_L);
+ ::KeyCode meta_r = XKeysymToKeycode(display, XK_Meta_R);
+ ::KeyCode alt_l = XKeysymToKeycode(display, XK_Alt_L);
+ ::KeyCode alt_r = XKeysymToKeycode(display, XK_Alt_R);
+ ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L);
+ ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R);
+ ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L);
+ ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R);
+ ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock);
+
+ int i, j;
+
+ mods = XGetModifierMapping(display);
+ if (mods == NULL)
+ return;
+
+ __current_alt_mask = 0;
+ __current_meta_mask = 0;
+ __current_super_mask = 0;
+ __current_hyper_mask = 0;
+ __current_numlock_mask = 0;
+
+ /* We skip the first three sets for Shift, Lock, and Control. The
+ remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5. */
+ for (i = 3; i < 8; i++)
+ {
+ for (j = 0; j < mods->max_keypermod; j++)
+ {
+ ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
+ if (! code) continue;
+ if (code == alt_l || code == alt_r)
+ __current_alt_mask |= (1 << i);
+ else if (code == meta_l || code == meta_r)
+ __current_meta_mask |= (1 << i);
+ else if (code == super_l || code == super_r)
+ __current_super_mask |= (1 << i);
+ else if (code == hyper_l || code == hyper_r)
+ __current_hyper_mask |= (1 << i);
+ else if (code == numlock)
+ __current_numlock_mask |= (1 << i);
+ }
+ }
+
+ /* Check whether there is a combine keys mapped to Meta */
+ if (__current_meta_mask == 0)
+ {
+ char buf [32];
+ XKeyEvent xkey;
+ KeySym keysym_l, keysym_r;
+
+ xkey.type = KeyPress;
+ xkey.display = display;
+ xkey.serial = 0L;
+ xkey.send_event = False;
+ xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
+ xkey.time = 0;
+ xkey.same_screen = False;
+ xkey.subwindow = None;
+ xkey.window = None;
+ xkey.root = DefaultRootWindow(display);
+ xkey.state = ShiftMask;
+
+ xkey.keycode = meta_l;
+ XLookupString(&xkey, buf, 32, &keysym_l, 0);
+ xkey.keycode = meta_r;
+ XLookupString(&xkey, buf, 32, &keysym_r, 0);
+
+ if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
+ __current_meta_mask = ShiftMask + __current_alt_mask;
+ else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
+ __current_meta_mask = ShiftMask + ControlMask;
+ }
+
+ XFreeModifiermap(mods);
+}
+
+static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ unsigned int state = 0;
+
+ initialize_modifier_bits(display);
+
+ if (scimkeymask & SCIM_KEY_ShiftMask) state |= ShiftMask;
+ if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
+ if (scimkeymask & SCIM_KEY_ControlMask) state |= ControlMask;
+ if (scimkeymask & SCIM_KEY_AltMask) state |= __current_alt_mask;
+ if (scimkeymask & SCIM_KEY_MetaMask) state |= __current_meta_mask;
+ if (scimkeymask & SCIM_KEY_SuperMask) state |= __current_super_mask;
+ if (scimkeymask & SCIM_KEY_HyperMask) state |= __current_hyper_mask;
+ if (scimkeymask & SCIM_KEY_NumLockMask) state |= __current_numlock_mask;
+
+ return state;
+}
+
+static XKeyEvent createKeyEvent(Display *display, Window &win,
+ Window &winRoot, bool press,
+ int keycode, int modifiers)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ XKeyEvent event;
+
+ event.display = display;
+ event.window = win;
+ event.root = winRoot;
+ event.subwindow = None;
+ event.time = CurrentTime;
+ event.x = 1;
+ event.y = 1;
+ event.x_root = 1;
+ event.y_root = 1;
+ event.same_screen = EINA_TRUE;
+ event.state = modifiers;
+ event.keycode = XKeysymToKeycode(display, keycode);
+ if (press)
+ event.type = KeyPress;
+ else
+ event.type = KeyRelease;
+ event.send_event = EINA_FALSE;
+ event.serial = 0;
+
+ return event;
+}
+
+static void _x_send_key_event(const KeyEvent &key)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ // Obtain the X11 display.
+ Display *display = XOpenDisplay(NULL);
+ if (display == NULL)
+ {
+ std::cerr << "XOpenDisplay failed\n";
+ return;
+ }
+
+ // Get the root window for the current display.
+ Window winRoot = 0;
+
+ // Find the window which has the current keyboard focus.
+ Window winFocus = 0;
+ int revert = RevertToParent;
+
+ XGetInputFocus(display, &winFocus, &revert);
+
+ // Send a fake key press event to the window.
+ XSelectInput(display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask);
+ XMapWindow(display, winFocus);
+
+ unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask);
+ XKeyEvent event;
+ if (key.is_key_press())
+ {
+ event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier);
+ XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
+ }
+ else
+ {
+ event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier);
+ XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
+ }
+
+ XCloseDisplay(display);
+}
+
+static void
+attach_instance(const IMEngineInstancePointer &si)
+{
+ si->signal_connect_show_preedit_string(
+ slot(slot_show_preedit_string));
+ si->signal_connect_show_aux_string(
+ slot(slot_show_aux_string));
+ si->signal_connect_show_lookup_table(
+ slot(slot_show_lookup_table));
+
+ si->signal_connect_hide_preedit_string(
+ slot(slot_hide_preedit_string));
+ si->signal_connect_hide_aux_string(
+ slot(slot_hide_aux_string));
+ si->signal_connect_hide_lookup_table(
+ slot(slot_hide_lookup_table));
+
+ si->signal_connect_update_preedit_caret(
+ slot(slot_update_preedit_caret));
+ si->signal_connect_update_preedit_string(
+ slot(slot_update_preedit_string));
+ si->signal_connect_update_aux_string(
+ slot(slot_update_aux_string));
+ si->signal_connect_update_lookup_table(
+ slot(slot_update_lookup_table));
+
+ si->signal_connect_commit_string(
+ slot(slot_commit_string));
+
+ si->signal_connect_forward_key_event(
+ slot(slot_forward_key_event));
+
+ si->signal_connect_register_properties(
+ slot(slot_register_properties));
+
+ si->signal_connect_update_property(
+ slot(slot_update_property));
+
+ si->signal_connect_beep(
+ slot(slot_beep));
+
+ si->signal_connect_start_helper(
+ slot(slot_start_helper));
+
+ si->signal_connect_stop_helper(
+ slot(slot_stop_helper));
+
+ si->signal_connect_send_helper_event(
+ slot(slot_send_helper_event));
+
+ si->signal_connect_get_surrounding_text(
+ slot(slot_get_surrounding_text));
+
+ si->signal_connect_delete_surrounding_text(
+ slot(slot_delete_surrounding_text));
+}
+
+// Implementation of slot functions
+static void
+slot_show_preedit_string(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ {
+ if (ic->impl->use_preedit)
+ {
+ if (!ic->impl->preedit_started)
+ {
+ ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
+ ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ ic->impl->preedit_started = true;
+ }
+ }
+ else
+ _panel_client.show_preedit_string(ic->id);
+ }
+}
+
+static void
+slot_show_aux_string(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.show_aux_string(ic->id);
+}
+
+static void
+slot_show_lookup_table(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.show_lookup_table(ic->id);
+}
+
+static void
+slot_hide_preedit_string(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ {
+ bool emit = false;
+ if (ic->impl->preedit_string.length())
+ {
+ ic->impl->preedit_string = WideString();
+ ic->impl->preedit_caret = 0;
+ ic->impl->preedit_attrlist.clear();
+ emit = true;
+ }
+ if (ic->impl->use_preedit)
+ {
+ if (emit)
+ {
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+ if (ic->impl->preedit_started)
+ {
+ ecore_imf_context_preedit_end_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+ ic->impl->preedit_started = false;
+ }
+ }
+ else
+ _panel_client.hide_preedit_string(ic->id);
+ }
+}
+
+static void
+slot_hide_aux_string(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.hide_aux_string(ic->id);
+}
+
+static void
+slot_hide_lookup_table(IMEngineInstanceBase *si)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.hide_lookup_table(ic->id);
+}
+
+static void
+slot_update_preedit_caret(IMEngineInstanceBase *si, int caret)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret)
+ {
+ ic->impl->preedit_caret = caret;
+ if (ic->impl->use_preedit)
+ {
+ if (!ic->impl->preedit_started)
+ {
+ ecore_imf_context_preedit_start_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ ic->impl->preedit_started = true;
+ }
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+ else
+ _panel_client.update_preedit_caret(ic->id, caret);
+ }
+}
+
+static void
+slot_update_preedit_string(IMEngineInstanceBase *si,
+ const WideString & str,
+ const AttributeList & attrs)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length()))
+ {
+ ic->impl->preedit_string = str;
+ ic->impl->preedit_attrlist = attrs;
+ if (ic->impl->use_preedit)
+ {
+ if (!ic->impl->preedit_started)
+ {
+ ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
+ ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ ic->impl->preedit_started = true;
+ }
+ ic->impl->preedit_caret = str.length();
+ ic->impl->preedit_updating = true;
+ ecore_imf_context_preedit_changed_event_add(ic->ctx);
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ ic->impl->preedit_updating = false;
+ }
+ else
+ {
+ _panel_client.update_preedit_string(ic->id, str, attrs);
+ }
+ }
+}
+
+static void
+slot_update_aux_string(IMEngineInstanceBase *si,
+ const WideString & str,
+ const AttributeList & attrs)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.update_aux_string(ic->id, str, attrs);
+}
+
+static void
+slot_commit_string(IMEngineInstanceBase *si,
+ const WideString & str)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->ctx)
+ {
+ ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(str).c_str());
+ ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
+ }
+}
+
+static void
+slot_forward_key_event(IMEngineInstanceBase *si,
+ const KeyEvent & key)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && _focused_ic == ic)
+ {
+ if (!_fallback_instance->process_key_event(key))
+ _x_send_key_event(key);
+ }
+}
+
+static void
+slot_update_lookup_table(IMEngineInstanceBase *si,
+ const LookupTable & table)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.update_lookup_table(ic->id, table);
+}
+
+static void
+slot_register_properties(IMEngineInstanceBase *si,
+ const PropertyList & properties)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.register_properties(ic->id, properties);
+}
+
+static void
+slot_update_property(IMEngineInstanceBase *si,
+ const Property & property)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ _panel_client.update_property(ic->id, property);
+}
+
+static void
+slot_beep(IMEngineInstanceBase *si __UNUSED__)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+}
+
+static void
+slot_start_helper(IMEngineInstanceBase *si,
+ const String &helper_uuid)
+{
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
+ << (ic ? ic->id : -1) << " ic=" << ic
+ << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
+
+ if (ic && ic->impl)
+ _panel_client.start_helper(ic->id, helper_uuid);
+}
+
+static void
+slot_stop_helper(IMEngineInstanceBase *si,
+ const String &helper_uuid)
+{
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n";
+
+ if (ic && ic->impl)
+ _panel_client.stop_helper(ic->id, helper_uuid);
+}
+
+static void
+slot_send_helper_event(IMEngineInstanceBase *si,
+ const String &helper_uuid,
+ const Transaction &trans)
+{
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
+ << (ic ? ic->id : -1) << " ic=" << ic
+ << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
+
+ if (ic && ic->impl)
+ _panel_client.send_helper_event(ic->id, helper_uuid, trans);
+}
+
+static bool
+slot_get_surrounding_text(IMEngineInstanceBase *si,
+ WideString &text,
+ int &cursor,
+ int maxlen_before,
+ int maxlen_after)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ {
+ char *surrounding = NULL;
+ int cursor_index;
+ if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index))
+ {
+ SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
+ SCIM_DEBUG_FRONTEND(2) << "Cursor Index : " << cursor_index <<"\n";
+ WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index)));
+ WideString after(utf8_mbstowcs(String(surrounding + cursor_index)));
+ if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length())
+ before = WideString(before.begin() + (before.length() - maxlen_before), before.end());
+ else if (maxlen_before == 0) before = WideString();
+ if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length())
+ after = WideString(after.begin(), after.begin() + maxlen_after);
+ else if (maxlen_after == 0) after = WideString();
+ text = before + after;
+ cursor = before.length();
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+slot_delete_surrounding_text(IMEngineInstanceBase *si,
+ int offset,
+ int len)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
+
+ if (ic && ic->impl && _focused_ic == ic)
+ {
+ Ecore_IMF_Event_Delete_Surrounding ev;
+ ev.ctx = _focused_ic->ctx;
+ ev.n_chars = len;
+ ev.offset = offset;
+ ecore_imf_context_delete_surrounding_event_add(_focused_ic->ctx, offset, len);
+ ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
+ return true;
+ }
+ return false;
+}
+
+static void
+reload_config_callback(const ConfigPointer &config)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ _frontend_hotkey_matcher.load_hotkeys(config);
+ _imengine_hotkey_matcher.load_hotkeys(config);
+
+ KeyEvent key;
+
+ scim_string_to_key(key,
+ config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
+ String("Shift+Control+Alt+Lock")));
+
+ _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
+ _valid_key_mask |= SCIM_KEY_ReleaseMask;
+ // Special treatment for two backslash keys on jp106 keyboard.
+ _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
+
+ _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
+ _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
+
+ // Get keyboard layout setting
+ // Flush the global config first, in order to load the new configs from disk.
+ scim_global_config_flush();
+
+ _keyboard_layout = scim_get_default_keyboard_layout();
+}
+
+static void
+fallback_commit_string_cb(IMEngineInstanceBase *si __UNUSED__,
+ const WideString &str)
+{
+ SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
+
+ if (_focused_ic && _focused_ic->impl)
+ {
+ ecore_imf_context_commit_event_add(_focused_ic->ctx, utf8_wcstombs(str).c_str());
+ ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
+ }
+}
+
diff --git a/src/modules/ecore/immodules/scim/scim_imcontext.h b/src/modules/ecore/immodules/scim/scim_imcontext.h
new file mode 100644
index 0000000000..72533e245d
--- /dev/null
+++ b/src/modules/ecore/immodules/scim/scim_imcontext.h
@@ -0,0 +1,42 @@
+#ifndef __ISF_IMF_CONTEXT_H
+#define __ISF_IMF_CONTEXT_H
+
+#include <Ecore_IMF.h>
+
+typedef struct _EcoreIMFContextISF EcoreIMFContextISF;
+typedef struct _EcoreIMFContextISFImpl EcoreIMFContextISFImpl;
+
+struct _EcoreIMFContextISF {
+ Ecore_IMF_Context *ctx;
+
+ EcoreIMFContextISFImpl *impl;
+
+ int id; /* Input Context id*/
+ struct _EcoreIMFContextISF *next;
+};
+
+void isf_imf_context_add (Ecore_IMF_Context *ctx);
+void isf_imf_context_del (Ecore_IMF_Context *ctx);
+void isf_imf_context_client_window_set (Ecore_IMF_Context *ctx, void *window);
+void isf_imf_context_client_canvas_set (Ecore_IMF_Context *ctx, void *window);
+void isf_imf_context_focus_in (Ecore_IMF_Context *ctx);
+void isf_imf_context_focus_out (Ecore_IMF_Context *ctx);
+void isf_imf_context_reset (Ecore_IMF_Context *ctx);
+void isf_imf_context_cursor_position_set (Ecore_IMF_Context *ctx, int cursor_pos);
+void isf_imf_context_cursor_location_set (Ecore_IMF_Context *ctx, int x, int y, int w, int h);
+void isf_imf_context_input_mode_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode);
+void isf_imf_context_preedit_string_get (Ecore_IMF_Context *ctx, char** str, int *cursor_pos);
+void isf_imf_context_preedit_string_with_attributes_get (Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos);
+void isf_imf_context_use_preedit_set (Ecore_IMF_Context* ctx, Eina_Bool use_preedit);
+Eina_Bool isf_imf_context_filter_event (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event);
+void isf_imf_context_prediction_allow_set (Ecore_IMF_Context* ctx, Eina_Bool prediction);
+void isf_imf_context_autocapital_type_set (Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type);
+void isf_imf_context_input_panel_layout_set (Ecore_IMF_Context* ctx, Ecore_IMF_Input_Panel_Layout layout);
+void isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx);
+void isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx);
+
+EcoreIMFContextISF* isf_imf_context_new (void);
+void isf_imf_context_shutdown (void);
+
+#endif /* __ISF_IMF_CONTEXT_H */
+
diff --git a/src/modules/ecore/immodules/scim/scim_module.cpp b/src/modules/ecore/immodules/scim/scim_module.cpp
new file mode 100644
index 0000000000..d77fb11f3a
--- /dev/null
+++ b/src/modules/ecore/immodules/scim/scim_module.cpp
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include "scim_imcontext.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+ static const Ecore_IMF_Context_Info isf_imf_info = {
+ "scim", /* ID */
+ "SCIM immodule for Ecore", /* Description */
+ "*", /* Default locales */
+ NULL, /* Canvas type */
+ 0 /* Canvas required */
+ };
+
+ static Ecore_IMF_Context_Class isf_imf_class = {
+ isf_imf_context_add, /* add */
+ isf_imf_context_del, /* del */
+ isf_imf_context_client_window_set, /* client_window_set */
+ isf_imf_context_client_canvas_set, /* client_canvas_set */
+ isf_imf_context_input_panel_show, /* input_panel_show, - show */
+ isf_imf_context_input_panel_hide, /* input_panel_hide, - hide */
+ isf_imf_context_preedit_string_get, /* get_preedit_string */
+ isf_imf_context_focus_in, /* focus_in */
+ isf_imf_context_focus_out, /* focus_out */
+ isf_imf_context_reset, /* reset */
+ isf_imf_context_cursor_position_set, /* cursor_position_set */
+ isf_imf_context_use_preedit_set, /* use_preedit_set */
+ isf_imf_context_input_mode_set, /* input_mode_set */
+ isf_imf_context_filter_event, /* filter_event */
+ isf_imf_context_preedit_string_with_attributes_get, /* preedit_string_with_attribute_get */
+ isf_imf_context_prediction_allow_set, /* prediction_allow_set */
+ isf_imf_context_autocapital_type_set, /* autocapital_type_set */
+ NULL, /* control panel show */
+ NULL, /* control panel hide */
+ NULL, /* input_panel_layout_set */
+ NULL, /* isf_imf_context_input_panel_layout_get, */
+ NULL, /* isf_imf_context_input_panel_language_set, */
+ NULL, /* isf_imf_context_input_panel_language_get, */
+ isf_imf_context_cursor_location_set, /* cursor_location_set */
+ NULL, /* input_panel_imdata_set */
+ NULL, /* input_panel_imdata_get */
+ NULL, /* input_panel_return_key_type_set */
+ NULL, /* input_panel_return_key_disabled_set */
+ NULL, /* input_panel_caps_lock_mode_set */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ static Ecore_IMF_Context *imf_module_create (void);
+ static Ecore_IMF_Context *imf_module_exit (void);
+
+ static Eina_Bool imf_module_init (void)
+ {
+ ecore_imf_module_register (&isf_imf_info, imf_module_create, imf_module_exit);
+ return EINA_TRUE;
+ }
+
+ static void imf_module_shutdown (void)
+ {
+ isf_imf_context_shutdown ();
+ }
+
+ static Ecore_IMF_Context *imf_module_create (void)
+ {
+ Ecore_IMF_Context *ctx = NULL;
+ EcoreIMFContextISF *ctxd = NULL;
+
+ ctxd = isf_imf_context_new ();
+ if (!ctxd)
+ {
+ printf ("isf_imf_context_new () failed!!!\n");
+ return NULL;
+ }
+
+ ctx = ecore_imf_context_new (&isf_imf_class);
+ if (!ctx)
+ {
+ delete ctxd;
+ return NULL;
+ }
+
+ ecore_imf_context_data_set (ctx, ctxd);
+
+ return ctx;
+ }
+
+ static Ecore_IMF_Context *imf_module_exit (void)
+ {
+ return NULL;
+ }
+
+ EINA_MODULE_INIT(imf_module_init);
+ EINA_MODULE_SHUTDOWN(imf_module_shutdown);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
diff --git a/src/modules/ecore/immodules/xim/ecore_imf_xim.c b/src/modules/ecore/immodules/xim/ecore_imf_xim.c
new file mode 100644
index 0000000000..64fc46c122
--- /dev/null
+++ b/src/modules/ecore/immodules/xim/ecore_imf_xim.c
@@ -0,0 +1,1555 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <Ecore_IMF.h>
+#include <Ecore_X.h>
+#include <X11/Xlib.h>
+#include <X11/Xlocale.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <langinfo.h>
+#include <assert.h>
+
+#define CLAMP(x, low, high) (x > high) ? high : (x < low) ? low : x
+#define _(x) x
+
+#ifdef ENABLE_XIM
+static Eina_List *open_ims = NULL;
+#endif
+
+#define FEEDBACK_MASK (XIMReverse | XIMUnderline | XIMHighlight)
+
+typedef struct _XIM_Im_Info XIM_Im_Info;
+
+typedef struct _Ecore_IMF_Context_Data Ecore_IMF_Context_Data;
+
+struct _XIM_Im_Info
+{
+ Ecore_X_Window win;
+ Ecore_IMF_Context_Data *user;
+ char *locale;
+ XIM im;
+ Eina_List *ics;
+ Eina_Bool reconnecting;
+ XIMStyles *xim_styles;
+ Eina_Bool supports_string_conversion : 1;
+ Eina_Bool supports_cursor : 1;
+};
+
+struct _Ecore_IMF_Context_Data
+{
+ Ecore_X_Window win;
+ long mask;
+ XIC ic; /* Input context for composed characters */
+ char *locale;
+ XIM_Im_Info *im_info;
+ int preedit_length;
+ int preedit_cursor;
+ Eina_Unicode *preedit_chars;
+ Eina_Bool use_preedit;
+ Eina_Bool finalizing;
+ Eina_Bool has_focus;
+ Eina_Bool in_toplevel;
+ XIMFeedback *feedbacks;
+
+ XIMCallback destroy_cb;
+
+ XIMCallback preedit_start_cb;
+ XIMCallback preedit_done_cb;
+ XIMCallback preedit_draw_cb;
+ XIMCallback preedit_caret_cb;
+};
+
+/* prototype */
+Ecore_IMF_Context_Data *imf_context_data_new();
+void imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data);
+
+#ifdef ENABLE_XIM
+static void add_feedback_attr(Eina_List **attrs,
+ const char *str,
+ XIMFeedback feedback,
+ int start_pos,
+ int end_pos);
+
+static void reinitialize_ic(Ecore_IMF_Context *ctx);
+static void set_ic_client_window(Ecore_IMF_Context *ctx,
+ Ecore_X_Window window);
+static int preedit_start_callback(XIC xic,
+ XPointer client_data,
+ XPointer call_data);
+static void preedit_done_callback(XIC xic,
+ XPointer client_data,
+ XPointer call_data);
+static int xim_text_to_utf8(Ecore_IMF_Context *ctx,
+ XIMText *xim_text,
+ char **text);
+static void preedit_draw_callback(XIC xic,
+ XPointer client_data,
+ XIMPreeditDrawCallbackStruct *call_data);
+static void preedit_caret_callback(XIC xic,
+ XPointer client_data,
+ XIMPreeditCaretCallbackStruct *call_data);
+static XVaNestedList preedit_callback_set(Ecore_IMF_Context *ctx);
+static XIC get_ic(Ecore_IMF_Context *ctx);
+static XIM_Im_Info *get_im(Ecore_X_Window window,
+ char *locale);
+static void xim_info_try_im(XIM_Im_Info *info);
+static void xim_info_display_closed(Ecore_X_Display *display,
+ int is_error,
+ XIM_Im_Info *info);
+static void xim_instantiate_callback(Display *display,
+ XPointer client_data,
+ XPointer call_data);
+static void setup_im(XIM_Im_Info *info);
+static void xim_destroy_callback(XIM xim,
+ XPointer client_data,
+ XPointer call_data);
+#endif
+
+#ifdef ENABLE_XIM
+static unsigned int
+utf8_offset_to_index(const char *str, int offset)
+{
+ int idx = 0;
+ int i;
+ for (i = 0; i < offset; i++)
+ {
+ eina_unicode_utf8_get_next(str, &idx);
+ }
+
+ return idx;
+}
+
+#endif
+
+static void
+_ecore_imf_context_xim_add(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data = NULL;
+
+ imf_context_data = imf_context_data_new();
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ imf_context_data->use_preedit = EINA_TRUE;
+ imf_context_data->finalizing = EINA_FALSE;
+ imf_context_data->has_focus = EINA_FALSE;
+ imf_context_data->in_toplevel = EINA_FALSE;
+
+ ecore_imf_context_data_set(ctx, imf_context_data);
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_del(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ imf_context_data->finalizing = EINA_TRUE;
+ if (imf_context_data->im_info && !imf_context_data->im_info->ics->next)
+ {
+ if (imf_context_data->im_info->reconnecting == EINA_TRUE)
+ {
+ Ecore_X_Display *dsp;
+ dsp = ecore_x_display_get();
+ XUnregisterIMInstantiateCallback(dsp,
+ NULL, NULL, NULL,
+ xim_instantiate_callback,
+ (XPointer)imf_context_data->im_info);
+ }
+ else if (imf_context_data->im_info->im)
+ {
+ XIMCallback im_destroy_callback;
+ im_destroy_callback.client_data = NULL;
+ im_destroy_callback.callback = NULL;
+ XSetIMValues(imf_context_data->im_info->im,
+ XNDestroyCallback, &im_destroy_callback,
+ NULL);
+ }
+ }
+
+ set_ic_client_window(ctx, 0);
+
+ imf_context_data_destroy(imf_context_data);
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx,
+ void *window)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window));
+#else
+ (void)ctx;
+ (void)window;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx,
+ char **str,
+ int *cursor_pos)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ char *utf8;
+ int len;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ if (imf_context_data->preedit_chars)
+ {
+ utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars,
+ &len);
+ if (str)
+ *str = utf8;
+ else
+ free(utf8);
+ }
+ else
+ {
+ if (str)
+ *str = NULL;
+ if (cursor_pos)
+ *cursor_pos = 0;
+ }
+
+ if (cursor_pos)
+ *cursor_pos = imf_context_data->preedit_cursor;
+#else
+ (void)ctx;
+ if (str)
+ *str = NULL;
+ if (cursor_pos)
+ *cursor_pos = 0;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
+ char **str,
+ Eina_List **attrs,
+ int *cursor_pos)
+{
+ EINA_LOG_DBG("in");
+
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
+
+ _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos);
+
+ if (!attrs) return;
+ if (!imf_context_data || !imf_context_data->feedbacks) return;
+
+ int i = 0;
+ XIMFeedback last_feedback = 0;
+ int start = -1;
+
+ for (i = 0; i < imf_context_data->preedit_length; i++)
+ {
+ XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK;
+
+ if (new_feedback != last_feedback)
+ {
+ if (start >= 0)
+ add_feedback_attr(attrs, *str, last_feedback, start, i);
+
+ last_feedback = new_feedback;
+ start = i;
+ }
+ }
+
+ if (start >= 0)
+ add_feedback_attr(attrs, *str, last_feedback, start, i);
+#else
+ (void)ctx;
+ if (str)
+ *str = NULL;
+ if (attrs)
+ *attrs = NULL;
+ if (cursor_pos)
+ *cursor_pos = 0;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ XIC ic;
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ ic = imf_context_data->ic;
+ imf_context_data->has_focus = EINA_TRUE;
+
+ if (ecore_imf_context_input_panel_enabled_get(ctx))
+ ecore_imf_context_input_panel_show(ctx);
+
+ if (ic)
+ {
+ char *str;
+
+#ifdef X_HAVE_UTF8_STRING
+ if ((str = Xutf8ResetIC(ic)))
+#else
+ if ((str = XmbResetIC(ic)))
+#endif
+ XFree(str);
+
+ XSetICFocus(ic);
+ }
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+#ifdef ENABLE_XIM
+ XIC ic;
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ if (imf_context_data->has_focus == EINA_TRUE)
+ {
+ imf_context_data->has_focus = EINA_FALSE;
+ ic = imf_context_data->ic;
+ if (ic)
+ XUnsetICFocus(ic);
+
+ if (ecore_imf_context_input_panel_enabled_get(ctx))
+ ecore_imf_context_input_panel_hide(ctx);
+ }
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+#ifdef ENABLE_XIM
+ XIC ic;
+ Ecore_IMF_Context_Data *imf_context_data;
+ char *result;
+
+ /* restore conversion state after resetting ic later */
+ XIMPreeditState preedit_state = XIMPreeditUnKnown;
+ XVaNestedList preedit_attr;
+ Eina_Bool have_preedit_state = EINA_FALSE;
+
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ ic = imf_context_data->ic;
+ if (!ic)
+ return;
+
+ if (imf_context_data->preedit_length == 0)
+ return;
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNPreeditState, &preedit_state,
+ NULL);
+ if (!XGetICValues(ic,
+ XNPreeditAttributes, preedit_attr,
+ NULL))
+ have_preedit_state = EINA_TRUE;
+
+ XFree(preedit_attr);
+
+ result = XmbResetIC(ic);
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNPreeditState, preedit_state,
+ NULL);
+ if (have_preedit_state)
+ XSetICValues(ic,
+ XNPreeditAttributes, preedit_attr,
+ NULL);
+
+ XFree(preedit_attr);
+
+ if (imf_context_data->feedbacks)
+ {
+ free(imf_context_data->feedbacks);
+ imf_context_data->feedbacks = NULL;
+ }
+
+ if (imf_context_data->preedit_length)
+ {
+ imf_context_data->preedit_length = 0;
+ free(imf_context_data->preedit_chars);
+ imf_context_data->preedit_chars = NULL;
+
+ ecore_imf_context_preedit_changed_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+
+ if (result)
+ {
+ char *result_utf8 = strdup(result);
+ if (result_utf8)
+ {
+ ecore_imf_context_commit_event_add(ctx, result_utf8);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
+ free(result_utf8);
+ }
+ }
+
+ XFree(result);
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx,
+ Eina_Bool use_preedit)
+{
+ EINA_LOG_DBG("in");
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ use_preedit = use_preedit != EINA_FALSE;
+
+ if (imf_context_data->use_preedit != use_preedit)
+ {
+ imf_context_data->use_preedit = use_preedit;
+ reinitialize_ic(ctx);
+ }
+#else
+ (void)ctx;
+ (void)use_preedit;
+#endif
+}
+
+#ifdef ENABLE_XIM
+static void
+add_feedback_attr(Eina_List **attrs,
+ const char *str,
+ XIMFeedback feedback,
+ int start_pos,
+ int end_pos)
+{
+ Ecore_IMF_Preedit_Attr *attr = NULL;
+
+ unsigned int start_index = utf8_offset_to_index(str, start_pos);
+ unsigned int end_index = utf8_offset_to_index(str, end_pos);
+
+ if (feedback & FEEDBACK_MASK)
+ {
+ attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
+ attr->start_index = start_index;
+ attr->end_index = end_index;
+ *attrs = eina_list_append(*attrs, (void *)attr);
+ }
+
+ if (feedback & XIMUnderline)
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
+
+ if (feedback & XIMReverse)
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
+
+ if (feedback & XIMHighlight)
+ attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
+}
+
+#endif
+
+static void
+_ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx,
+ int x, int y, int w, int h)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ XIC ic;
+ XVaNestedList preedit_attr;
+ XPoint spot;
+
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+ ic = imf_context_data->ic;
+ if (!ic)
+ return;
+
+ spot.x = x;
+ spot.y = y + h;
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ NULL);
+ XSetICValues(ic,
+ XNPreeditAttributes, preedit_attr,
+ NULL);
+
+ XFree(preedit_attr);
+#else
+ (void)ctx;
+ (void)x;
+ (void)y;
+ (void)h;
+#endif
+ (void)(w); // yes w is unused, but only a bi-product of the algorithm
+}
+
+static void
+_ecore_imf_context_xim_input_panel_show(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ ecore_x_e_virtual_keyboard_state_set
+ (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
+#else
+ (void)ctx;
+#endif
+}
+
+static void
+_ecore_imf_context_xim_input_panel_hide(Ecore_IMF_Context *ctx)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ ecore_x_e_virtual_keyboard_state_set
+ (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
+#else
+ (void)ctx;
+#endif
+}
+
+#ifdef ENABLE_XIM
+static unsigned int
+_ecore_x_event_reverse_modifiers(unsigned int state)
+{
+ unsigned int modifiers = 0;
+
+ /**< "Control" is pressed */
+ if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
+ modifiers |= ECORE_X_MODIFIER_CTRL;
+
+ /**< "Alt" is pressed */
+ if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
+ modifiers |= ECORE_X_MODIFIER_ALT;
+
+ /**< "Shift" is pressed */
+ if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
+ modifiers |= ECORE_X_MODIFIER_SHIFT;
+
+ /**< "Win" (between "Ctrl" and "Alt") is pressed */
+ if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
+ modifiers |= ECORE_X_MODIFIER_WIN;
+
+ /**< "AltGr" is pressed */
+ if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
+ modifiers |= ECORE_X_MODIFIER_ALTGR;
+
+ return modifiers;
+}
+
+static unsigned int
+_ecore_x_event_reverse_locks(unsigned int state)
+{
+ unsigned int locks = 0;
+
+ /**< "Num" lock is active */
+ if (state & ECORE_IMF_KEYBOARD_LOCK_NUM)
+ locks |= ECORE_X_LOCK_NUM;
+
+ if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS)
+ locks |= ECORE_X_LOCK_CAPS;
+
+ if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
+ locks |= ECORE_X_LOCK_SCROLL;
+
+ return locks;
+}
+
+static KeyCode
+_keycode_get(Ecore_X_Display *dsp,
+ const char *keyname)
+{
+ KeyCode keycode;
+
+ // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname));
+ if (strcmp(keyname, "Keycode-0") == 0)
+ keycode = 0;
+ else
+ keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname));
+
+ return keycode;
+}
+
+#endif
+
+static Eina_Bool
+_ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
+ Ecore_IMF_Event_Type type,
+ Ecore_IMF_Event *event)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+#ifdef ENABLE_XIM
+ Ecore_IMF_Context_Data *imf_context_data;
+ XIC ic;
+
+ Ecore_X_Display *dsp;
+ Ecore_X_Window win;
+
+ int val;
+ char compose_buffer[256];
+ KeySym sym;
+ char *compose = NULL;
+ char *tmp = NULL;
+ Eina_Bool result = EINA_FALSE;
+
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ if (!imf_context_data) return EINA_FALSE;
+ ic = imf_context_data->ic;
+ if (!ic)
+ ic = get_ic(ctx);
+
+ if (type == ECORE_IMF_EVENT_KEY_DOWN)
+ {
+ XKeyPressedEvent xev;
+ Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
+ EINA_LOG_DBG("ECORE_IMF_EVENT_KEY_DOWN");
+
+ dsp = ecore_x_display_get();
+ win = imf_context_data->win;
+
+ xev.type = KeyPress;
+ xev.serial = 0; /* hope it doesn't matter */
+ xev.send_event = 0;
+ xev.display = dsp;
+ xev.window = win;
+ xev.root = ecore_x_window_root_get(win);
+ xev.subwindow = win;
+ xev.time = ev->timestamp;
+ xev.x = xev.x_root = 0;
+ xev.y = xev.y_root = 0;
+ xev.state = 0;
+ xev.state |= _ecore_x_event_reverse_modifiers(ev->modifiers);
+ xev.state |= _ecore_x_event_reverse_locks(ev->locks);
+ xev.keycode = _keycode_get(dsp, ev->keyname);
+ xev.same_screen = True;
+
+ if (ic)
+ {
+ Status mbstatus;
+#ifdef X_HAVE_UTF8_STRING
+ val = Xutf8LookupString(ic,
+ &xev,
+ compose_buffer,
+ sizeof(compose_buffer) - 1,
+ &sym,
+ &mbstatus);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ val = XmbLookupString(ic,
+ &xev,
+ compose_buffer,
+ sizeof(compose_buffer) - 1,
+ &sym,
+ &mbstatus);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ if (mbstatus == XBufferOverflow)
+ {
+ tmp = malloc(sizeof (char) * (val + 1));
+ if (!tmp)
+ return EINA_FALSE;
+
+ compose = tmp;
+
+#ifdef X_HAVE_UTF8_STRING
+ val = Xutf8LookupString(ic,
+ &xev,
+ tmp,
+ val,
+ &sym,
+ &mbstatus);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ val = XmbLookupString(ic,
+ &xev,
+ tmp,
+ val,
+ &sym,
+ &mbstatus);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ if (val > 0)
+ {
+ tmp[val] = '\0';
+#ifndef X_HAVE_UTF8_STRING
+ compose = eina_str_convert(nl_langinfo(CODESET),
+ "UTF-8", tmp);
+ free(tmp);
+ tmp = compose;
+#endif /* ifndef X_HAVE_UTF8_STRING */
+ }
+ else
+ compose = NULL;
+ }
+ else if (val > 0)
+ {
+ compose_buffer[val] = '\0';
+#ifdef X_HAVE_UTF8_STRING
+ compose = strdup(compose_buffer);
+#else /* ifdef X_HAVE_UTF8_STRING */
+ compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8",
+ compose_buffer);
+#endif /* ifdef X_HAVE_UTF8_STRING */
+ }
+ }
+ else
+ {
+ compose = strdup(ev->compose);
+ }
+
+ if (compose)
+ {
+ Eina_Unicode *unicode;
+ int len;
+ unicode = eina_unicode_utf8_to_unicode(compose, &len);
+ if (!unicode) abort();
+ if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
+ {
+ ecore_imf_context_commit_event_add(ctx, compose);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
+ result = EINA_TRUE;
+ }
+ free(compose);
+ free(unicode);
+ }
+ }
+
+ return result;
+#else
+ (void)ctx;
+ (void)type;
+ (void)event;
+ return EINA_FALSE;
+#endif
+}
+
+static const Ecore_IMF_Context_Info xim_info = {
+ .id = "xim",
+ .description = _("X input method"),
+ .default_locales = "ko:ja:th:zh",
+ .canvas_type = "evas",
+ .canvas_required = 1,
+};
+
+static Ecore_IMF_Context_Class xim_class = {
+ .add = _ecore_imf_context_xim_add,
+ .del = _ecore_imf_context_xim_del,
+ .client_window_set = _ecore_imf_context_xim_client_window_set,
+ .client_canvas_set = NULL,
+ .show = _ecore_imf_context_xim_input_panel_show,
+ .hide = _ecore_imf_context_xim_input_panel_hide,
+ .preedit_string_get = _ecore_imf_context_xim_preedit_string_get,
+ .focus_in = _ecore_imf_context_xim_focus_in,
+ .focus_out = _ecore_imf_context_xim_focus_out,
+ .reset = _ecore_imf_context_xim_reset,
+ .cursor_position_set = NULL,
+ .use_preedit_set = _ecore_imf_context_xim_use_preedit_set,
+ .input_mode_set = NULL,
+ .filter_event = _ecore_imf_context_xim_filter_event,
+ .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get,
+ .prediction_allow_set = NULL,
+ .autocapital_type_set = NULL,
+ .control_panel_show = NULL,
+ .control_panel_hide = NULL,
+ .input_panel_layout_set = NULL,
+ .input_panel_layout_get = NULL,
+ .input_panel_language_set = NULL,
+ .input_panel_language_get = NULL,
+ .cursor_location_set = _ecore_imf_context_xim_cursor_location_set,
+ .input_panel_imdata_set = NULL,
+ .input_panel_imdata_get = NULL,
+ .input_panel_return_key_type_set = NULL,
+ .input_panel_return_key_disabled_set = NULL,
+ .input_panel_caps_lock_mode_set = NULL
+};
+
+static Ecore_IMF_Context *
+xim_imf_module_create(void)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+ Ecore_IMF_Context *ctx = NULL;
+
+ ctx = ecore_imf_context_new(&xim_class);
+ if (!ctx)
+ goto error;
+
+ return ctx;
+
+error:
+ free(ctx);
+ return NULL;
+}
+
+static Ecore_IMF_Context *
+xim_imf_module_exit(void)
+{
+ return NULL;
+}
+
+Eina_Bool
+ecore_imf_xim_init(void)
+{
+ EINA_LOG_DBG("%s in", __FUNCTION__);
+ eina_init();
+ ecore_x_init(NULL);
+ ecore_imf_module_register(&xim_info,
+ xim_imf_module_create,
+ xim_imf_module_exit);
+
+ return EINA_TRUE;
+}
+
+void
+ecore_imf_xim_shutdown(void)
+{
+#ifdef ENABLE_XIM
+ while (open_ims)
+ {
+ XIM_Im_Info *info = open_ims->data;
+ Ecore_X_Display *display = ecore_x_display_get();
+
+ xim_info_display_closed(display, EINA_FALSE, info);
+ }
+#endif
+
+ ecore_x_shutdown();
+ eina_shutdown();
+}
+
+EINA_MODULE_INIT(ecore_imf_xim_init);
+EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
+
+#ifdef ENABLE_XIM
+/*
+ * internal functions
+ */
+Ecore_IMF_Context_Data *
+imf_context_data_new()
+{
+ Ecore_IMF_Context_Data *imf_context_data = NULL;
+ char *locale;
+
+ locale = setlocale(LC_CTYPE, "");
+ if (!locale) return NULL;
+
+ if (!XSupportsLocale()) return NULL;
+
+ imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
+
+ imf_context_data->locale = strdup(locale);
+ if (!imf_context_data->locale) goto error;
+
+ return imf_context_data;
+error:
+ imf_context_data_destroy(imf_context_data);
+ return NULL;
+}
+
+void
+imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
+{
+ if (!imf_context_data)
+ return;
+
+ if (imf_context_data->ic)
+ XDestroyIC(imf_context_data->ic);
+
+ free(imf_context_data->preedit_chars);
+
+ if (imf_context_data->feedbacks)
+ {
+ free(imf_context_data->feedbacks);
+ imf_context_data->feedbacks = NULL;
+ }
+
+ free(imf_context_data->locale);
+ free(imf_context_data);
+}
+
+static int
+preedit_start_callback(XIC xic EINA_UNUSED,
+ XPointer client_data,
+ XPointer call_data EINA_UNUSED)
+{
+ EINA_LOG_DBG("in");
+ Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ if (!imf_context_data) return -1;
+
+ if (imf_context_data->finalizing == EINA_FALSE)
+ {
+ ecore_imf_context_preedit_start_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+ }
+ return -1;
+}
+
+static void
+preedit_done_callback(XIC xic EINA_UNUSED,
+ XPointer client_data,
+ XPointer call_data EINA_UNUSED)
+{
+ EINA_LOG_DBG("in");
+ Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ if (imf_context_data->preedit_length)
+ {
+ imf_context_data->preedit_length = 0;
+ free(imf_context_data->preedit_chars);
+ imf_context_data->preedit_chars = NULL;
+ ecore_imf_context_preedit_changed_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+
+ if (imf_context_data->finalizing == EINA_FALSE)
+ {
+ ecore_imf_context_preedit_end_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+ }
+}
+
+/* FIXME */
+static int
+xim_text_to_utf8(Ecore_IMF_Context *ctx EINA_UNUSED,
+ XIMText *xim_text,
+ char **text)
+{
+ int text_length = 0;
+ char *result = NULL;
+
+ if (xim_text && xim_text->string.multi_byte)
+ {
+ if (xim_text->encoding_is_wchar)
+ {
+ EINA_LOG_WARN("Wide character return from Xlib not currently supported");
+ *text = NULL;
+ return 0;
+ }
+
+ /* XXX Convert to UTF-8 */
+ result = strdup(xim_text->string.multi_byte);
+ if (result)
+ {
+ text_length = eina_unicode_utf8_get_len(result);
+ if (text_length != xim_text->length)
+ {
+ EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
+ }
+ }
+ else
+ {
+ EINA_LOG_WARN("Error converting text from IM to UCS-4");
+ *text = NULL;
+ return 0;
+ }
+
+ *text = result;
+ return text_length;
+ }
+ else
+ {
+ *text = NULL;
+ return 0;
+ }
+}
+
+static void
+preedit_draw_callback(XIC xic EINA_UNUSED,
+ XPointer client_data,
+ XIMPreeditDrawCallbackStruct *call_data)
+{
+ EINA_LOG_DBG("in");
+ Eina_Bool ret = EINA_FALSE;
+ Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
+ Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
+ XIMText *t = call_data->text;
+ char *tmp;
+ Eina_Unicode *new_text = NULL;
+ Eina_UStrbuf *preedit_bufs = NULL;
+ int new_text_length;
+ int i = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ preedit_bufs = eina_ustrbuf_new();
+ if (imf_context_data->preedit_chars)
+ {
+ ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
+ if (ret == EINA_FALSE) goto done;
+ }
+
+ new_text_length = xim_text_to_utf8(ctx, t, &tmp);
+ if (tmp)
+ {
+ int tmp_len;
+ new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
+ free(tmp);
+ }
+
+ if (t == NULL)
+ {
+ /* delete string */
+ ret = eina_ustrbuf_remove(preedit_bufs,
+ call_data->chg_first, call_data->chg_length);
+ }
+ else if (call_data->chg_length == 0)
+ {
+ /* insert string */
+ ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
+ }
+ else if (call_data->chg_length > 0)
+ {
+ /* replace string */
+ ret = eina_ustrbuf_remove(preedit_bufs,
+ call_data->chg_first, call_data->chg_length);
+ if (ret == EINA_FALSE) goto done;
+
+ ret = eina_ustrbuf_insert_n(preedit_bufs, new_text,
+ new_text_length, call_data->chg_first);
+ if (ret == EINA_FALSE) goto done;
+ }
+ else
+ {
+ ret = EINA_FALSE;
+ }
+
+done:
+ if (ret == EINA_TRUE)
+ {
+ free(imf_context_data->preedit_chars);
+ imf_context_data->preedit_chars =
+ eina_ustrbuf_string_steal(preedit_bufs);
+ imf_context_data->preedit_length =
+ eina_unicode_strlen(imf_context_data->preedit_chars);
+
+ if (imf_context_data->feedbacks)
+ {
+ free(imf_context_data->feedbacks);
+ imf_context_data->feedbacks = NULL;
+ }
+
+ if (imf_context_data->preedit_length > 0)
+ {
+ imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
+
+ for (i = 0; i < imf_context_data->preedit_length; i++)
+ imf_context_data->feedbacks[i] = t->feedback[i];
+ }
+
+ ecore_imf_context_preedit_changed_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+
+ free(new_text);
+ eina_ustrbuf_free(preedit_bufs);
+}
+
+static void
+preedit_caret_callback(XIC xic EINA_UNUSED,
+ XPointer client_data,
+ XIMPreeditCaretCallbackStruct *call_data)
+{
+ EINA_LOG_DBG("in");
+ Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ if (call_data->direction == XIMAbsolutePosition)
+ {
+ // printf("call_data->position:%d\n", call_data->position);
+ imf_context_data->preedit_cursor = call_data->position;
+ if (imf_context_data->finalizing == EINA_FALSE)
+ {
+ ecore_imf_context_preedit_changed_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+ }
+}
+
+static XVaNestedList
+preedit_callback_set(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+
+ imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
+ imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
+
+ imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
+ imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
+
+ imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
+ imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
+
+ imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
+ imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
+
+ return XVaCreateNestedList(0,
+ XNPreeditStartCallback,
+ &imf_context_data->preedit_start_cb,
+ XNPreeditDoneCallback,
+ &imf_context_data->preedit_done_cb,
+ XNPreeditDrawCallback,
+ &imf_context_data->preedit_draw_cb,
+ XNPreeditCaretCallback,
+ &imf_context_data->preedit_caret_cb,
+ NULL);
+}
+
+static XIC
+get_ic(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Context_Data *imf_context_data;
+ XIC ic;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
+
+ ic = imf_context_data->ic;
+ if (!ic)
+ {
+ XIM_Im_Info *im_info = imf_context_data->im_info;
+ XVaNestedList preedit_attr = NULL;
+ XIMStyle im_style = 0;
+ XPoint spot = { 0, 0 };
+ char *name = NULL;
+
+ if (!im_info)
+ {
+ EINA_LOG_WARN("Doesn't open XIM.");
+ return NULL;
+ }
+
+ // supported styles
+#if 0
+ int i;
+ if (im_info->xim_styles)
+ {
+ for (i = 0; i < im_info->xim_styles->count_styles; i++)
+ {
+ printf("%i: ", i);
+ if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks)
+ printf("XIMPreeditCallbacks | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition)
+ printf("XIMPreeditPosition | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea)
+ printf("XIMPreeditArea | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing)
+ printf("XIMPreeditNothing | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone)
+ printf("XIMPreeditNone | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMStatusArea)
+ printf("XIMStatusArea | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks)
+ printf("XIMStatusCallbacks | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing)
+ printf("XIMStatusNothing | ");
+ if (im_info->xim_styles->supported_styles[i] & XIMStatusNone)
+ printf("XIMStatusNone | ");
+ printf("\n");
+ }
+ }
+#endif
+ // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
+ // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
+ // "Root" = XIMPreeditNothing | XIMStatusNothing
+
+ if (imf_context_data->use_preedit == EINA_TRUE)
+ {
+ if (im_info->supports_cursor)
+ {
+ // kinput2 DOES do this...
+ XFontSet fs;
+ char **missing_charset_list;
+ int missing_charset_count;
+ char *def_string;
+
+ im_style |= XIMPreeditPosition;
+ im_style |= XIMStatusNothing;
+ fs = XCreateFontSet(ecore_x_display_get(),
+ "fixed",
+ &missing_charset_list,
+ &missing_charset_count,
+ &def_string);
+ preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ XNFontSet, fs,
+ NULL);
+ }
+ else
+ {
+ im_style |= XIMPreeditCallbacks;
+ im_style |= XIMStatusNothing;
+ preedit_attr = preedit_callback_set(ctx);
+ }
+ name = XNPreeditAttributes;
+ }
+ else
+ {
+ im_style |= XIMPreeditNothing;
+ im_style |= XIMStatusNothing;
+ }
+
+ if (!im_info->xim_styles)
+ {
+ EINA_LOG_WARN("No XIM styles supported! Wanted %#llx",
+ (unsigned long long)im_style);
+ im_style = 0;
+ }
+ else
+ {
+ XIMStyle fallback = 0;
+ int i;
+
+ for (i = 0; i < im_info->xim_styles->count_styles; i++)
+ {
+ XIMStyle cur = im_info->xim_styles->supported_styles[i];
+ if (cur == im_style)
+ break;
+ else if (cur == (XIMPreeditNothing | XIMStatusNothing))
+ /* TODO: fallback is just that or the anyone? */
+ fallback = cur;
+ }
+
+ if (i == im_info->xim_styles->count_styles)
+ {
+ if (fallback)
+ {
+ EINA_LOG_WARN("Wanted XIM style %#llx not found, "
+ "using fallback %#llx instead.",
+ (unsigned long long)im_style,
+ (unsigned long long)fallback);
+ im_style = fallback;
+ }
+ else
+ {
+ EINA_LOG_WARN("Wanted XIM style %#llx not found, "
+ "no fallback supported.",
+ (unsigned long long)im_style);
+ im_style = 0;
+ }
+ }
+ }
+
+ if ((im_info->im) && (im_style))
+ {
+ ic = XCreateIC(im_info->im,
+ XNInputStyle, im_style,
+ XNClientWindow, imf_context_data->win,
+ name, preedit_attr, NULL);
+ }
+ XFree(preedit_attr);
+ if (ic)
+ {
+ unsigned long mask = 0xaaaaaaaa;
+ XGetICValues(ic,
+ XNFilterEvents, &mask,
+ NULL);
+ imf_context_data->mask = mask;
+ ecore_x_event_mask_set(imf_context_data->win, mask);
+ }
+
+ imf_context_data->ic = ic;
+ if (ic && imf_context_data->has_focus == EINA_TRUE)
+ XSetICFocus(ic);
+ }
+
+ return ic;
+}
+
+static void
+reinitialize_ic(Ecore_IMF_Context *ctx)
+{
+ Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ XIC ic = imf_context_data->ic;
+ if (ic)
+ {
+ XDestroyIC(ic);
+ imf_context_data->ic = NULL;
+ if (imf_context_data->preedit_length)
+ {
+ imf_context_data->preedit_length = 0;
+ free(imf_context_data->preedit_chars);
+ imf_context_data->preedit_chars = NULL;
+ ecore_imf_context_preedit_changed_event_add(ctx);
+ ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+ }
+ }
+}
+
+static void
+set_ic_client_window(Ecore_IMF_Context *ctx,
+ Ecore_X_Window window)
+{
+ EINA_LOG_DBG("in");
+ Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
+ Ecore_X_Window old_win;
+
+ EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
+
+ /* reinitialize IC */
+ reinitialize_ic(ctx);
+
+ old_win = imf_context_data->win;
+ EINA_LOG_DBG("old_win:%d window:%d ", old_win, window);
+ if (old_win != 0 && old_win != window) /* XXX how do check window... */
+ {
+ XIM_Im_Info *info;
+ info = imf_context_data->im_info;
+ info->ics = eina_list_remove(info->ics, imf_context_data);
+ if (imf_context_data->im_info)
+ imf_context_data->im_info->user = NULL;
+ imf_context_data->im_info = NULL;
+ }
+
+ imf_context_data->win = window;
+
+ if (window) /* XXX */
+ {
+ XIM_Im_Info *info = NULL;
+ info = get_im(window, imf_context_data->locale);
+ imf_context_data->im_info = info;
+ imf_context_data->im_info->ics =
+ eina_list_prepend(imf_context_data->im_info->ics,
+ imf_context_data);
+ if (imf_context_data->im_info)
+ imf_context_data->im_info->user = imf_context_data;
+ }
+}
+
+static XIM_Im_Info *
+get_im(Ecore_X_Window window,
+ char *locale)
+{
+ EINA_LOG_DBG("in");
+
+ Eina_List *l;
+ XIM_Im_Info *im_info = NULL;
+ XIM_Im_Info *info = NULL;
+ EINA_LIST_FOREACH (open_ims, l, im_info)
+ {
+ if (strcmp(im_info->locale, locale) == 0)
+ {
+ if (im_info->im)
+ {
+ return im_info;
+ }
+ else
+ {
+ info = im_info;
+ break;
+ }
+ }
+ }
+
+ if (!info)
+ {
+ info = calloc(1, sizeof(XIM_Im_Info));
+ if (!info) return NULL;
+ open_ims = eina_list_prepend(open_ims, info);
+ info->win = window;
+ info->locale = strdup(locale);
+ info->reconnecting = EINA_FALSE;
+ }
+
+ xim_info_try_im(info);
+ return info;
+}
+
+/* initialize info->im */
+static void
+xim_info_try_im(XIM_Im_Info *info)
+{
+ Ecore_X_Display *dsp;
+
+ assert(info->im == NULL);
+ if (info->reconnecting == EINA_TRUE)
+ return;
+
+ if (XSupportsLocale())
+ {
+ if (!XSetLocaleModifiers(""))
+ EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()");
+ dsp = ecore_x_display_get();
+ info->im = XOpenIM(dsp, NULL, NULL, NULL);
+ if (!info->im)
+ {
+ XRegisterIMInstantiateCallback(dsp,
+ NULL, NULL, NULL,
+ xim_instantiate_callback,
+ (XPointer)info);
+ info->reconnecting = EINA_TRUE;
+ return;
+ }
+ setup_im(info);
+ }
+}
+
+static void
+xim_info_display_closed(Ecore_X_Display *display EINA_UNUSED,
+ int is_error EINA_UNUSED,
+ XIM_Im_Info *info)
+{
+ Eina_List *ics, *tmp_list;
+ Ecore_IMF_Context *ctx;
+
+ open_ims = eina_list_remove(open_ims, info);
+
+ ics = info->ics;
+ info->ics = NULL;
+
+ EINA_LIST_FOREACH (ics, tmp_list, ctx)
+ set_ic_client_window(ctx, 0);
+
+ EINA_LIST_FREE (ics, ctx)
+ {
+ Ecore_IMF_Context_Data *imf_context_data;
+ imf_context_data = ecore_imf_context_data_get(ctx);
+ imf_context_data_destroy(imf_context_data);
+ }
+
+ free(info->locale);
+
+ if (info->im)
+ XCloseIM(info->im);
+
+ free(info);
+}
+
+static void
+xim_instantiate_callback(Display *display,
+ XPointer client_data,
+ XPointer call_data EINA_UNUSED)
+{
+ XIM_Im_Info *info = (XIM_Im_Info *)client_data;
+ XIM im = NULL;
+
+ im = XOpenIM(display, NULL, NULL, NULL);
+
+ if (!im)
+ {
+ fprintf(stderr, "Failed to connect to IM\n");
+ return;
+ }
+
+ info->im = im;
+ setup_im(info);
+
+ XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
+ xim_instantiate_callback,
+ (XPointer)info);
+ info->reconnecting = EINA_FALSE;
+}
+
+static void
+setup_im(XIM_Im_Info *info)
+{
+ XIMValuesList *ic_values = NULL;
+ XIMCallback im_destroy_callback;
+
+ if (!info->im)
+ return;
+
+ im_destroy_callback.client_data = (XPointer)info;
+ im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
+ XSetIMValues(info->im,
+ XNDestroyCallback, &im_destroy_callback,
+ NULL);
+
+ XGetIMValues(info->im,
+ XNQueryInputStyle, &info->xim_styles,
+ XNQueryICValuesList, &ic_values,
+ NULL);
+
+ if (ic_values)
+ {
+ int i;
+
+ for (i = 0; i < ic_values->count_values; i++)
+ {
+ if (!strcmp(ic_values->supported_values[i],
+ XNStringConversionCallback))
+ info->supports_string_conversion = EINA_TRUE;
+ if (!strcmp(ic_values->supported_values[i],
+ XNCursor))
+ info->supports_cursor = EINA_TRUE;
+ }
+#if 0
+ printf("values........\n");
+ for (i = 0; i < ic_values->count_values; i++)
+ printf("%s\n", ic_values->supported_values[i]);
+ printf("styles........\n");
+ for (i = 0; i < info->xim_styles->count_styles; i++)
+ printf("%lx\n", info->xim_styles->supported_styles[i]);
+#endif
+ XFree(ic_values);
+ }
+}
+
+static void
+xim_destroy_callback(XIM xim EINA_UNUSED,
+ XPointer client_data,
+ XPointer call_data EINA_UNUSED)
+{
+ XIM_Im_Info *info = (XIM_Im_Info *)client_data;
+
+ if (info->user) info->user->ic = NULL;
+ info->im = NULL;
+// reinitialize_ic(ctx);
+ xim_info_try_im(info);
+
+ return;
+}
+
+#endif /* ENABLE_XIM */
diff --git a/src/utils/ecore/makekeys.c b/src/utils/ecore/makekeys.c
new file mode 100644
index 0000000000..a057fa2c65
--- /dev/null
+++ b/src/utils/ecore/makekeys.c
@@ -0,0 +1,326 @@
+/* Portions of this code are Copyright 1990, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/keysymdef.h>
+
+#define TBLNUM 4000
+#define MIN_REHASH 15
+#define MATCHES 10
+
+typedef struct _Info Info;
+static struct _Info
+{
+ char *name;
+ long unsigned int val;
+} info[TBLNUM];
+
+/* local function prototypes */
+static int _parseline(const char *buf, char *key, long unsigned int *val, char *prefix);
+
+/* local variables */
+static char tab[TBLNUM];
+static unsigned short offsets[TBLNUM];
+static unsigned short indexes[TBLNUM];
+static long unsigned int values[TBLNUM];
+static char buf[1024];
+static int ksnum = 0;
+
+int
+main(int argc, char **argv)
+{
+ int max_rehash = 0;
+ unsigned long sig;
+ int i = 0, j = 0, k = 0, l = 0, z = 0;
+ FILE *fptr;
+ char *name = NULL, c;
+ int first = 0, num_found = 0;
+ int best_max_rehash = 0, best_z = 0;
+ long unsigned int val;
+ char key[128], prefix[128];
+
+ for (l = 1; l < argc; l++)
+ {
+ if (!(fptr = fopen(argv[l], "r")))
+ {
+ fprintf(stderr, "Could not open %s\n", argv[l]);
+ continue;
+ }
+
+ while (fgets(buf, sizeof(buf), fptr))
+ {
+ if (!_parseline(buf, key, &val, prefix))
+ continue;
+
+ if (val == XK_VoidSymbol) val = 0;
+ if (val > 0x1fffffff)
+ {
+ fprintf(stderr, "Ignoring illegal keysym (%s %lx)\n",
+ key, val);
+ continue;
+ }
+
+ if (!(name = malloc(strlen(prefix) + strlen(key) + 1)))
+ {
+ fprintf(stderr, "Makekeys: Out Of Memory !!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sprintf(name, "%s%s", prefix, key);
+ info[ksnum].name = name;
+ info[ksnum].val = val;
+ ksnum++;
+ if (ksnum == TBLNUM)
+ {
+ fprintf(stderr, "Makekeys: Too Many Keysyms!!\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ fclose(fptr);
+ }
+
+ printf("/* This file is generated from keysymdef.h. */\n");
+ printf("/* Do Not Edit !! */\n\n");
+
+ best_max_rehash = ksnum;
+ num_found = 0;
+ for (z = ksnum; z < TBLNUM; z++)
+ {
+ max_rehash = 0;
+ for (name = tab, i = z; --i >= 0;)
+ *name++ = 0;
+ for (i = 0; i < ksnum; i++)
+ {
+ name = info[i].name;
+ sig = 0;
+ while ((c = *name++))
+ sig = (sig << 1) + c;
+ first = j = sig % z;
+ for (k = 0; tab[j]; k++)
+ {
+ j += (first + 1);
+ if (j >= z) j -= z;
+ if (j == first) goto next1;
+ }
+ tab[j] = 1;
+ if (k > max_rehash) max_rehash = k;
+ }
+ if (max_rehash < MIN_REHASH)
+ {
+ if (max_rehash < best_max_rehash)
+ {
+ best_max_rehash = max_rehash;
+ best_z = z;
+ }
+ num_found++;
+ if (num_found >= MATCHES)
+ break;
+ }
+next1: ;
+ }
+
+ z = best_z;
+ if (z == 0)
+ {
+ fprintf(stderr, "Makekeys: Failed to find small enough hash !!\n"
+ "Try increasing TBLNUM in makekeys.c\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("#ifdef NEED_KEYSYM_TABLE\n");
+ printf("const unsigned char _ecore_xcb_keytable[] = {\n");
+ printf("0,\n");
+ k = 1;
+ for (i = 0; i < ksnum; i++)
+ {
+ name = info[i].name;
+ sig = 0;
+ while ((c = *name++))
+ sig = (sig << 1) + c;
+ first = j = sig % z;
+ while (offsets[j])
+ {
+ j += (first + 1);
+ if (j >= z) j -= z;
+ }
+ offsets[j] = k;
+ indexes[i] = k;
+ val = info[i].val;
+ printf("0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, ",
+ (sig >> 8) & 0xff, sig & 0xff,
+ (val >> 24) & 0xff, (val >> 16) & 0xff,
+ (val >> 8) & 0xff, val & 0xff);
+ for (name = info[i].name, k += 7; (c = *name++); k++)
+ printf("'%c',", c);
+ printf((i == (ksnum - 1)) ? "0\n" : "0,\n");
+ }
+
+ printf("};\n\n");
+ printf("#define KTABLESIZE %d\n", z);
+ printf("#define KMAXHASH %d\n", (best_max_rehash + 1));
+ printf("\n");
+ printf("static const unsigned short hashString[KTABLESIZE] = {\n");
+
+ for (i = 0; i < z;)
+ {
+ printf("0x%.4x", offsets[i]);
+ i++;
+ if (i == z) break;
+ printf((i & 7) ? ", " : ",\n");
+ }
+
+ printf("\n");
+ printf("};\n");
+ printf("#endif\n");
+
+ best_max_rehash = ksnum;
+ num_found = 0;
+ for (z = ksnum; z < TBLNUM; z++)
+ {
+ max_rehash = 0;
+ for (name = tab, i = z; --i >= 0;)
+ *name++ = 0;
+ for (i = 0; i < ksnum; i++)
+ {
+ val = info[i].val;
+ first = j = val % z;
+ for (k = 0; tab[j]; k++)
+ {
+ if (values[j] == val) goto skip1;
+ j += (first + 1);
+ if (j >= z) j -= z;
+ if (j == first) goto next2;
+ }
+ tab[j] = 1;
+ values[j] = val;
+ if (k > max_rehash) max_rehash = k;
+skip1: ;
+ }
+ if (max_rehash < MIN_REHASH)
+ {
+ if (max_rehash < best_max_rehash)
+ {
+ best_max_rehash = max_rehash;
+ best_z = z;
+ }
+ num_found++;
+ if (num_found >= MATCHES) break;
+ }
+next2: ;
+ }
+
+ z = best_z;
+ if (z == 0)
+ {
+ fprintf(stderr, "Makekeys: Failed to find small enough hash !!\n"
+ "Try increasing TBLNUM in makekeys.c\n");
+ exit(EXIT_FAILURE);
+ }
+ for (i = z; --i >= 0;)
+ offsets[i] = 0;
+
+ for (i = 0; i < ksnum; i++)
+ {
+ val = info[i].val;
+ first = j = val % z;
+ while (offsets[j])
+ {
+ if (values[j] == val) goto skip2;
+ j += (first + 1);
+ if (j >= z) j -= z;
+ }
+ offsets[j] = indexes[i] + 2;
+ values[j] = val;
+skip2: ;
+ }
+
+ printf("\n");
+ printf("#ifdef NEED_VTABLE\n");
+ printf("#define VTABLESIZE %d\n", z);
+ printf("#define VMAXHASH %d\n", best_max_rehash + 1);
+ printf("\n");
+ printf("static const unsigned short hashKeysym[VTABLESIZE] = {\n");
+ for (i = 0; i < z;)
+ {
+ printf("0x%.4x", offsets[i]);
+ i++;
+ if (i == z) break;
+ printf((i & 7) ? ", " : ",\n");
+ }
+ printf("\n");
+ printf("};\n");
+ printf("#endif\n");
+
+ return 0;
+}
+
+/* local functions */
+static int
+_parseline(const char *buf, char *key, long unsigned int *val, char *prefix)
+{
+ int i = 0;
+ char alias[128];
+ char *tmp = NULL, *tmpa = NULL;
+
+ /* try to match XK_foo first */
+ i = sscanf(buf, "#define %127s 0x%lx", key, val);
+ if ((i == 2) && (tmp = strstr(key, "XK_")))
+ {
+ memcpy(prefix, key, (tmp - key));
+ prefix[tmp - key] = '\0';
+ tmp += 3;
+ memmove(key, tmp, strlen(tmp) + 1);
+ return 1;
+ }
+
+ /* try to match an alias */
+ i = sscanf(buf, "#define %127s %127s", key, alias);
+ if (((i == 2) && (tmp = strstr(key, "XK_"))) &&
+ (tmpa = strstr(alias, "XK_")))
+ {
+ memcpy(prefix, key, (tmp - key));
+ prefix[tmp - key] = '\0';
+ tmp += 3;
+ memmove(key, tmp, strlen(tmp) + 1);
+ memmove(tmpa, tmpa + 3, strlen(tmpa + 3) + 1);
+
+ for (i = ksnum - 1; i >= 0; i--)
+ {
+ if (!strcmp(info[i].name, alias))
+ {
+ *val = info[i].val;
+ return 1;
+ }
+ }
+ fprintf(stderr, "Cannot find matching definition %s for keysym %s%s\n",
+ alias, prefix, key);
+ }
+
+ return 0;
+}
diff --git a/src/utils/ecore/mkks.sh b/src/utils/ecore/mkks.sh
new file mode 100755
index 0000000000..666924258a
--- /dev/null
+++ b/src/utils/ecore/mkks.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+cat $* | awk 'BEGIN { \
+ printf "/*\n * This file is generated from %s. Do not edit.\n */\n", \
+ "$(INCLUDESRC)/keysymdef.h";\
+} \
+/^#define/ { \
+ len = length($2)-3; \
+ printf("{ \"%s\", %s },\n", substr($2,4,len), $3); \
+}'