diff --git a/configure.ac b/configure.ac index fb1995a0e..d19da098d 100644 --- a/configure.ac +++ b/configure.ac @@ -798,6 +798,7 @@ AC_E_OPTIONAL_MODULE([backlight], true) AC_E_OPTIONAL_MODULE([tasks], true) AC_E_OPTIONAL_MODULE([conf_randr], true) AC_E_OPTIONAL_MODULE([xkbswitch], true) +AC_E_OPTIONAL_MODULE([tiling], true) SUSPEND="" HIBERNATE="" @@ -954,6 +955,8 @@ src/modules/tasks/Makefile src/modules/tasks/module.desktop src/modules/xkbswitch/Makefile src/modules/xkbswitch/module.desktop +src/modules/tiling/Makefile +src/modules/tiling/module.desktop src/preload/Makefile data/Makefile data/images/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 637b8d19a..a0e334936 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -250,6 +250,9 @@ src/modules/systray/e_mod_main.c src/modules/shot/e_mod_main.c src/modules/tasks/e_mod_main.c src/modules/tasks/e_mod_config.c +src/modules/tiling/e_mod_config.c +src/modules/tiling/e_mod_tiling.c +src/modules/tiling/e_mod_tiling.h src/modules/xkbswitch/e_mod_main.c src/modules/xkbswitch/e_mod_config.c src/modules/xkbswitch/e_mod_parse.c diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 77a89435c..83bf77018 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -195,6 +195,10 @@ if USE_MODULE_XKBSWITCH SUBDIRS += xkbswitch endif +if USE_MODULE_TILING +SUBDIRS += tiling +endif + #if HAVE_WAYLAND_DRM # SUBDIRS += wl_drm #endif diff --git a/src/modules/tiling/AUTHORS b/src/modules/tiling/AUTHORS new file mode 100644 index 000000000..1ff354024 --- /dev/null +++ b/src/modules/tiling/AUTHORS @@ -0,0 +1,2 @@ +Boris Faure +Based on original Tiling module by Michael Stapelberg diff --git a/src/modules/tiling/ChangeLog b/src/modules/tiling/ChangeLog new file mode 100644 index 000000000..1e4d6a9ac --- /dev/null +++ b/src/modules/tiling/ChangeLog @@ -0,0 +1,15 @@ +v0.9 December 11, 2011 + * restore border and maximized state when untiling + * add setting to stack in rows or columns + * toggle between rows and columns + * add setting to choose key hints + * add setting whether to display the window title + +v0.5 July 17, 2011 + * swap windows + * move windows + * change focus to identified window + * move transitions + +v0.1 May 14, 2011 + * basic tiling diff --git a/src/modules/tiling/Makefile.am b/src/modules/tiling/Makefile.am new file mode 100644 index 000000000..2daa7ad46 --- /dev/null +++ b/src/modules/tiling/Makefile.am @@ -0,0 +1,38 @@ +MAINTAINERCLEANFILES = Makefile.in module.desktop +MODULE = tiling + +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = e-module-$(MODULE).edj module.desktop + +EXTRA_DIST = $(files_DATA) \ + e-module-$(MODULE).edc \ + module.desktop.in \ + images/module_icon.png + +EDJE_CC = @edje_cc@ +EDJE_FLAGS = -id $(top_srcdir)/src/modules/$(MODULE)/images \ + @EDJE_DEF@ + +e-module-$(MODULE).edj: e-module-$(MODULE).edc + $(EDJE_CC) $(EDJE_FLAGS) $< $@ + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_builddir)/src/bin \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la +module_la_SOURCES = e_mod_tiling.c \ + e_mod_tiling.h \ + e_mod_config.c + +module_la_LIBADD = @e_libs@ @dlopen_libs@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/tiling/README b/src/modules/tiling/README new file mode 100644 index 000000000..1f653800c --- /dev/null +++ b/src/modules/tiling/README @@ -0,0 +1,18 @@ +A tiling module for the Enlightenment Window Manager + +Concept +======= + +Each desktop can have from 1 to 8 (vertical) columns. +Windows are then resized and moved to use as much as columns as configured. + +When there are more windows than possible columns, the remaining windows are +packed in the last column. + +Resizing or moving a window will try to resize or move the column it is in. + +What is needed? +=============== + +An up-to-date enlightenment environment. +… diff --git a/src/modules/tiling/TODO b/src/modules/tiling/TODO new file mode 100644 index 000000000..75465fb79 --- /dev/null +++ b/src/modules/tiling/TODO @@ -0,0 +1,12 @@ + +--- v1.0 +[ ] Respect more ICCCM +[ ] Show how many columns are configured. (?) +[ ] Remove remaining bugs ☺. + +--- v0.9 +[X] Toggle between horizontal and vertical columns +[X] Handle correctly multiple screens +[X] Setting whether to display the window title +[X] Setting to choose hint keys +[X] Save original border and restore it when untiling diff --git a/src/modules/tiling/e-module-tiling.edc b/src/modules/tiling/e-module-tiling.edc new file mode 100644 index 000000000..fcda1811a --- /dev/null +++ b/src/modules/tiling/e-module-tiling.edc @@ -0,0 +1,2861 @@ +images { + image: "module_icon.png" COMP; + + image: "arrow_n.png" COMP; + image: "arrow_nw.png" COMP; + image: "arrow_w.png" COMP; + image: "arrow_sw.png" COMP; + image: "arrow_s.png" COMP; + image: "arrow_se.png" COMP; + image: "arrow_e.png" COMP; + image: "arrow_ne.png" COMP; +} +collections { + group { + name: "icon"; + parts { + part { + name: "image"; + mouse_events: 0; + description { + state: "default" 0.0; + aspect: 1.0 1.0; + aspect_preference: BOTH; + image.normal: "module_icon.png"; + } + } + } + } + + group { name: "modules/tiling/move/left/composite"; // {{{ + min: 101 54; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 101 54; + max: 101 54; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_nw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 77 29; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 101 54; + to: "_"; + } + image.normal: "arrow_nw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 42 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 63 29; + to: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_sw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 29; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 54; + to: "_"; + } + image.normal: "arrow_sw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_nw"; + target: "arrow_w"; + target: "arrow_sw"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_nw"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_sw"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_w"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_nw"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_sw"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_w"; + } + } + } // }}} + group { name: "modules/tiling/move/left"; // {{{ + min: 101 54; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 101 54; + max: 101 54; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_nw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 77 29; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 101 54; + to: "_"; + } + image.normal: "arrow_nw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 42 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 63 29; + to: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_sw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 29; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 54; + to: "_"; + } + image.normal: "arrow_sw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_nw"; + target: "arrow_w"; + target: "arrow_sw"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_nw"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_sw"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_w"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_nw"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_sw"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_w"; + } + } + } // }}} + + group { name: "modules/tiling/move/down/composite"; // {{{ + min: 54 101; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 54 101; + max: 54 101; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_sw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 29 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 53 25; + to: "_"; + } + image.normal: "arrow_sw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 38; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 29 59; + to: "_"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_se"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 29 76; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 53 101; + to: "_"; + } + image.normal: "arrow_se.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_sw"; + target: "arrow_s"; + target: "arrow_se"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_sw"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_se"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_s"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_sw"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_se"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_s"; + } + } + } // }}} + group { name: "modules/tiling/move/down"; // {{{ + min: 54 101; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 54 101; + max: 54 101; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_sw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 29 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 53 25; + to: "_"; + } + image.normal: "arrow_sw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 38; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 29 59; + to: "_"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_se"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 29 76; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 53 101; + to: "_"; + } + image.normal: "arrow_se.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_sw"; + target: "arrow_s"; + target: "arrow_se"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_sw"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_se"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_s"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_sw"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_se"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_s"; + } + } + } // }}} + + group { name: "modules/tiling/move/right/composite"; // {{{ + min: 101 54; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 101 54; + max: 101 54; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_se"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 25; + to: "_"; + } + image.normal: "arrow_se.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 38 25; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 59 54; + to: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_ne"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 77 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 101 24; + to: "_"; + } + image.normal: "arrow_ne.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_se"; + target: "arrow_e"; + target: "arrow_ne"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_se"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_ne"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_e"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_se"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_ne"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_e"; + } + } + } // }}} + group { name: "modules/tiling/move/right"; // {{{ + min: 101 54; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 101 54; + max: 101 54; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_se"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 25; + to: "_"; + } + image.normal: "arrow_se.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 38 25; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 59 54; + to: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_ne"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 77 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 101 24; + to: "_"; + } + image.normal: "arrow_ne.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_se"; + target: "arrow_e"; + target: "arrow_ne"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_se"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_ne"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_e"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_se"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_ne"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_e"; + } + } + } // }}} + + group { name: "modules/tiling/move/up/composite"; // {{{ + min: 54 101; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 54 101; + max: 54 101; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_ne"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 76; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 101; + to: "_"; + } + image.normal: "arrow_ne.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 25 38; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 54 59; + to: "_"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_nw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 25; + to: "_"; + } + image.normal: "arrow_nw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_ne"; + target: "arrow_n"; + target: "arrow_nw"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_ne"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_nw"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_n"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_ne"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_nw"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_n"; + } + } + } // }}} + group { name: "modules/tiling/move/up"; // {{{ + min: 54 101; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 54 101; + max: 54 101; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_ne"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 76; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 101; + to: "_"; + } + image.normal: "arrow_ne.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 25 38; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 54 59; + to: "_"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_nw"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 0; + offset: 24 25; + to: "_"; + } + image.normal: "arrow_nw.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_ne"; + target: "arrow_n"; + target: "arrow_nw"; + after: "in1a"; + } + program { + name: "in1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_ne"; + after: "in2a"; + after: "in2b"; + } + program { + name: "in1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_nw"; + } + program { + name: "in2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_n"; + after: "in3a"; + after: "in3b"; + } + program { + name: "in2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.4; + target: "arrow_ne"; + } + program { + name: "in3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.4; + target: "arrow_nw"; + after: "in1a"; + after: "in1b"; + } + program { + name: "in3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.6; + target: "arrow_n"; + } + } + } // }}} + + group { name: "modules/tiling/transition/horizontal/composite"; // {{{ + min: 29 221; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 29 221; + max: 29 221; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_n_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 1 0; + offset: 0 21; + to: "_"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_3"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_3"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_2"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_2"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_1"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_1"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 10; + to_x: "_"; + to_y: "arrow_n_0"; + } + rel2 { + relative: 1 1; + offset: 0 31; + to_x: "_"; + to_y: "arrow_n_0"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_0"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_0"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_1"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_1"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_2"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_2"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_n_0"; + target: "arrow_n_1"; + target: "arrow_n_2"; + target: "arrow_n_3"; + target: "arrow_s_0"; + target: "arrow_s_1"; + target: "arrow_s_2"; + target: "arrow_s_3"; + after: "n0a"; + after: "s0a"; + } + program { + name: "n0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_0"; + after: "n1a"; + after: "n1b"; + } + program { + name: "n0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_3"; + } + program { + name: "n1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_1"; + after: "n2a"; + after: "n2b"; + } + program { + name: "n1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_0"; + } + program { + name: "n2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_2"; + after: "n3a"; + after: "n3b"; + } + program { + name: "n2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_1"; + } + program { + name: "n3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_3"; + after: "n0a"; + after: "n0b"; + } + program { + name: "n3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_2"; + } + program { + name: "s0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_0"; + after: "s1a"; + after: "s1b"; + } + program { + name: "s0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_3"; + } + program { + name: "s1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_1"; + after: "s2a"; + after: "s2b"; + } + program { + name: "s1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_0"; + } + program { + name: "s2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_2"; + after: "s3a"; + after: "s3b"; + } + program { + name: "s2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_1"; + } + program { + name: "s3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_3"; + after: "s0a"; + after: "s0b"; + } + program { + name: "s3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_2"; + } + } + } // }}} + group { name: "modules/tiling/transition/horizontal"; // {{{ + min: 29 221; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 29 221; + max: 29 221; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_n_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 1 0; + offset: 0 21; + to: "_"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_3"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_3"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_2"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_2"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_n_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_n_1"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_n_1"; + } + image.normal: "arrow_n.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 10; + to_x: "_"; + to_y: "arrow_n_0"; + } + rel2 { + relative: 1 1; + offset: 0 31; + to_x: "_"; + to_y: "arrow_n_0"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_0"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_0"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_1"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_1"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_s_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 1; + offset: 0 6; + to_x: "_"; + to_y: "arrow_s_2"; + } + rel2 { + relative: 1 1; + offset: 0 27; + to_x: "_"; + to_y: "arrow_s_2"; + } + image.normal: "arrow_s.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_n_0"; + target: "arrow_n_1"; + target: "arrow_n_2"; + target: "arrow_n_3"; + target: "arrow_s_0"; + target: "arrow_s_1"; + target: "arrow_s_2"; + target: "arrow_s_3"; + after: "n0a"; + after: "s0a"; + } + program { + name: "n0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_0"; + after: "n1a"; + after: "n1b"; + } + program { + name: "n0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_3"; + } + program { + name: "n1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_1"; + after: "n2a"; + after: "n2b"; + } + program { + name: "n1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_0"; + } + program { + name: "n2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_2"; + after: "n3a"; + after: "n3b"; + } + program { + name: "n2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_1"; + } + program { + name: "n3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_n_3"; + after: "n0a"; + after: "n0b"; + } + program { + name: "n3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_n_2"; + } + program { + name: "s0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_0"; + after: "s1a"; + after: "s1b"; + } + program { + name: "s0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_3"; + } + program { + name: "s1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_1"; + after: "s2a"; + after: "s2b"; + } + program { + name: "s1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_0"; + } + program { + name: "s2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_2"; + after: "s3a"; + after: "s3b"; + } + program { + name: "s2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_1"; + } + program { + name: "s3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_s_3"; + after: "s0a"; + after: "s0b"; + } + program { + name: "s3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_s_2"; + } + } + } // }}} + + group { name: "modules/tiling/transition/vertical/composite"; // {{{ + min: 221 29; + data { + item: "shaped" "1"; + } + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 221 29; + max: 221 29; + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_w_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 1; + offset: 21 0; + to: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_3"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_3"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_2"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_2"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_1"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_1"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 10 0; + to_x: "arrow_w_0"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 31 0; + to_x: "arrow_w_0"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_0"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_0"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_1"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_1"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_2"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_2"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_w_0"; + target: "arrow_w_1"; + target: "arrow_w_2"; + target: "arrow_w_3"; + target: "arrow_e_0"; + target: "arrow_e_1"; + target: "arrow_e_2"; + target: "arrow_e_3"; + after: "w0a"; + after: "e0a"; + } + program { + name: "w0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_0"; + after: "w1a"; + after: "w1b"; + } + program { + name: "w0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_3"; + } + program { + name: "w1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_1"; + after: "w2a"; + after: "w2b"; + } + program { + name: "w1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_0"; + } + program { + name: "w2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_2"; + after: "w3a"; + after: "w3b"; + } + program { + name: "w2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_1"; + } + program { + name: "w3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_3"; + after: "w0a"; + after: "w0b"; + } + program { + name: "w3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_2"; + } + program { + name: "e0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_0"; + after: "e1a"; + after: "e1b"; + } + program { + name: "e0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_3"; + } + program { + name: "e1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_1"; + after: "e2a"; + after: "e2b"; + } + program { + name: "e1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_0"; + } + program { + name: "e2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_2"; + after: "e3a"; + after: "e3b"; + } + program { + name: "e2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_1"; + } + program { + name: "e3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_3"; + after: "e0a"; + after: "e0b"; + } + program { + name: "e3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_2"; + } + } + } // }}} + group { name: "modules/tiling/transition/vertical"; // {{{ + min: 221 29; + parts { + part { + name: "_"; + type: RECT; + mouse_events: 0; + description { + min: 221 29; + max: 221 29; + state: "default" 0.0; + color: 0 0 0 255; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1 1; + offset: -1 -1; + } + } + } + part { + name: "arrow_w_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0 0; + offset: 0 0; + to: "_"; + } + rel2 { + relative: 0 1; + offset: 21 0; + to: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_3"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_3"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_2"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_2"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_w_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_w_1"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_w_1"; + to_y: "_"; + } + image.normal: "arrow_w.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_0"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 10 0; + to_x: "arrow_w_0"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 31 0; + to_x: "arrow_w_0"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_1"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_0"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_0"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_2"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_1"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_1"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { + name: "arrow_e_3"; + mouse_events: 0; + description { + state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 1 0; + offset: 6 0; + to_x: "arrow_e_2"; + to_y: "_"; + } + rel2 { + relative: 1 1; + offset: 27 0; + to_x: "arrow_e_2"; + to_y: "_"; + } + image.normal: "arrow_e.png"; + fill.smooth: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + } + programs { + program { + name: "init"; + signal: "load"; + source: ""; + action: STATE_SET "default" 0.0; + target: "arrow_w_0"; + target: "arrow_w_1"; + target: "arrow_w_2"; + target: "arrow_w_3"; + target: "arrow_e_0"; + target: "arrow_e_1"; + target: "arrow_e_2"; + target: "arrow_e_3"; + after: "w0a"; + after: "e0a"; + } + program { + name: "w0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_0"; + after: "w1a"; + after: "w1b"; + } + program { + name: "w0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_3"; + } + program { + name: "w1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_1"; + after: "w2a"; + after: "w2b"; + } + program { + name: "w1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_0"; + } + program { + name: "w2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_2"; + after: "w3a"; + after: "w3b"; + } + program { + name: "w2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_1"; + } + program { + name: "w3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_w_3"; + after: "w0a"; + after: "w0b"; + } + program { + name: "w3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_w_2"; + } + program { + name: "e0a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_0"; + after: "e1a"; + after: "e1b"; + } + program { + name: "e0b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_3"; + } + program { + name: "e1a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_1"; + after: "e2a"; + after: "e2b"; + } + program { + name: "e1b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_0"; + } + program { + name: "e2a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_2"; + after: "e3a"; + after: "e3b"; + } + program { + name: "e2b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_1"; + } + program { + name: "e3a"; + action: STATE_SET "visible" 0.0; + transition: SINUSOIDAL 0.25; + target: "arrow_e_3"; + after: "e0a"; + after: "e0b"; + } + program { + name: "e3b"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.75; + target: "arrow_e_2"; + } + } + } // }}} +} diff --git a/src/modules/tiling/e_mod_config.c b/src/modules/tiling/e_mod_config.c new file mode 100644 index 000000000..0f424f23d --- /dev/null +++ b/src/modules/tiling/e_mod_config.c @@ -0,0 +1,333 @@ +#include "e_mod_tiling.h" + +/* HACK: Needed to get subobjs of the widget. Is there a better way? */ +typedef struct _E_Widget_Smart_Data E_Widget_Smart_Data; + +struct _E_Widget_Smart_Data +{ + Evas_Object *parent_obj; + Evas_Coord x, y, w, h; + Evas_Coord minw, minh; + Eina_List *subobjs; +}; + +/* Some defines to make coding with the e_widget_* easier for + * configuration panel */ +#define RADIO(title, value, radiogroup) \ + e_widget_radio_add(evas, _(title), value, radiogroup) +#define LIST_ADD(list, object) \ + e_widget_list_object_append(list, object, 1, 1, 0.5) + +struct _Config_vdesk * +get_vdesk(Eina_List *vdesks, + int x, + int y, + unsigned int zone_num) +{ + for (Eina_List *l = vdesks; l; l = l->next) { + struct _Config_vdesk *vd = l->data; + + if (!vd) + continue; + if (vd->nb_stacks < 0 || vd->nb_stacks > TILING_MAX_STACKS) + vd->nb_stacks = 0; + if (vd->x == x && vd->y == y && vd->zone_num == zone_num) + return vd; + } + + return NULL; +} + +/* + * Fills the E_Config_Dialog-struct with the data currently in use + * + */ +static void * +_create_data(E_Config_Dialog *cfd) +{ + E_Config_Dialog_Data *cfdata = E_NEW(E_Config_Dialog_Data, 1); + + /* Because we save a lot of lines here by using memcpy, + * the structs have to be ordered the same */ + memcpy(cfdata, tiling_g.config, sizeof(Config)); + cfdata->config.keyhints = strdup(tiling_g.config->keyhints); + + /* Handle things which can't be easily memcpy'd */ + cfdata->config.vdesks = NULL; + + for (Eina_List *l = tiling_g.config->vdesks; l; l = l->next) { + struct _Config_vdesk *vd = l->data, + *newvd; + + if (!vd) + continue; + + newvd = E_NEW(struct _Config_vdesk, 1); + newvd->x = vd->x; + newvd->y = vd->y; + newvd->zone_num = vd->zone_num; + newvd->nb_stacks = vd->nb_stacks; + newvd->use_rows = vd->use_rows; + + cfdata->config.vdesks = eina_list_append(cfdata->config.vdesks, + newvd); + } + + return cfdata; +} + +static void +_free_data(E_Config_Dialog *cfd, + E_Config_Dialog_Data *cfdata) +{ + eina_list_free(cfdata->config.vdesks); + free(cfdata->config.keyhints); + free(cfdata); +} + +static void +_fill_zone_config(E_Zone *zone, + E_Config_Dialog_Data *cfdata) +{ + Evas *evas = cfdata->evas; + + /* Clear old entries first */ + evas_object_del(cfdata->o_desklist); + + cfdata->o_desklist = e_widget_list_add(evas, 1, 0); + + for (int i = 0; i < zone->desk_y_count * zone->desk_x_count; i++) { + E_Desk *desk = zone->desks[i]; + struct _Config_vdesk *vd; + Evas_Object *list, *slider, *radio; + E_Radio_Group *rg; + + if (!desk) + continue; + + vd = get_vdesk(cfdata->config.vdesks, desk->x, desk->y, zone->num); + if (!vd) { + vd = E_NEW(struct _Config_vdesk, 1); + vd->x = desk->x; + vd->y = desk->y; + vd->zone_num = zone->num; + vd->nb_stacks = 0; + vd->use_rows = 0; + + cfdata->config.vdesks = eina_list_append(cfdata->config.vdesks, + vd); + } + + list = e_widget_list_add(evas, false, true); + + LIST_ADD(list, e_widget_label_add(evas, desk->name)); + slider = e_widget_slider_add(evas, 1, 0, _("%1.0f"), + 0.0, 8.0, 1.0, 0, NULL, + &vd->nb_stacks, 150); + LIST_ADD(list, slider); + + rg = e_widget_radio_group_new(&vd->use_rows); + radio = e_widget_radio_add(evas, _("columns"), 0, rg); + LIST_ADD(list, radio); + radio = e_widget_radio_add(evas, _("rows"), 1, rg); + LIST_ADD(list, radio); + + LIST_ADD(cfdata->o_desklist, list); + } + + /* Get the correct sizes of desklist and scrollframe */ + LIST_ADD(cfdata->osf, cfdata->o_desklist); +} + +static void +_cb_zone_change(void *data, + Evas_Object *obj) +{ + int n; + E_Config_Dialog_Data *cfdata = data; + E_Zone *zone; + + if (!cfdata || !cfdata->o_zonelist) + return; + + n = e_widget_ilist_selected_get(cfdata->o_zonelist); + zone = e_widget_ilist_nth_data_get(cfdata->o_zonelist, n); + if (!zone) + return; + _fill_zone_config(zone, cfdata); +} + +static Evas_Object * +_basic_create_widgets(E_Config_Dialog *cfd, + Evas *evas, + E_Config_Dialog_Data *cfdata) +{ + Evas_Object *o, *oc, *of; + E_Container *con = e_container_current_get(e_manager_current_get()); + E_Zone *zone; + + o = e_widget_list_add(evas, 0, 0); + + /* General settings */ + of = e_widget_framelist_add(evas, _("General"), 0); + e_widget_framelist_object_append(of, + e_widget_check_add(evas, _("Tile dialog windows as well"), + &cfdata->config.tile_dialogs)); + e_widget_framelist_object_append(of, + e_widget_check_add(evas, _("Show window titles"), + &cfdata->config.show_titles)); + oc = e_widget_list_add(evas, false, true); + e_widget_list_object_append(oc, + e_widget_label_add(evas, _("Key hints")), 1, 0, 0.5); + e_widget_list_object_append(oc, + e_widget_entry_add(evas, &cfdata->config.keyhints, NULL, NULL, NULL), + 1, 1, 0.5); + e_widget_framelist_object_append(of, oc); + + LIST_ADD(o, of); + + /* Virtual desktop settings */ + of = e_widget_framelist_add(evas, _("Virtual Desktops"), 0); + e_widget_label_add(evas, + _("Number of columns used to tile per desk" + " (0 → tiling disabled):")); + cfdata->osf = e_widget_list_add(evas, 0, 1); + + /* Zone list */ + cfdata->o_zonelist = e_widget_ilist_add(evas, 0, 0, NULL); + e_widget_ilist_multi_select_set(cfdata->o_zonelist, false); + e_widget_size_min_set(cfdata->o_zonelist, 100, 100); + e_widget_on_change_hook_set(cfdata->o_zonelist, _cb_zone_change, cfdata); + for (Eina_List *l = con->zones; l; l = l->next) { + if (!(zone = l->data)) + continue; + e_widget_ilist_append(cfdata->o_zonelist, NULL, zone->name, NULL, zone, NULL); + } + e_widget_ilist_go(cfdata->o_zonelist); + e_widget_ilist_thaw(cfdata->o_zonelist); + + LIST_ADD(cfdata->osf, cfdata->o_zonelist); + + /* List of individual tiling modes */ + cfdata->evas = evas; + + _fill_zone_config(con->zones->data, cfdata); + + e_widget_ilist_selected_set(cfdata->o_zonelist, 0); + + e_widget_framelist_object_append(of, cfdata->osf); + + LIST_ADD(o, of); + + return o; +} + +static int +_basic_apply_data(E_Config_Dialog *cfd, + E_Config_Dialog_Data *cfdata) +{ + struct _Config_vdesk *vd; + + tiling_g.config->tile_dialogs = cfdata->config.tile_dialogs; + tiling_g.config->show_titles = cfdata->config.show_titles; + if (strcmp(tiling_g.config->keyhints, cfdata->config.keyhints)) { + free(tiling_g.config->keyhints); + if (!cfdata->config.keyhints || !*cfdata->config.keyhints) { + tiling_g.config->keyhints = strdup(tiling_g.default_keyhints); + } else { + char *c = cfdata->config.keyhints; + int len = strlen(cfdata->config.keyhints); + + /* Remove duplicates */ + while (*c) { + char *f = c + 1; + + while ((f = strchr(f, *c))) { + *f = cfdata->config.keyhints[--len]; + cfdata->config.keyhints[len] = '\0'; + } + c++; + } + tiling_g.config->keyhints = strdup(cfdata->config.keyhints); + } + } + + /* Check if the layout for one of the vdesks has changed */ + for (Eina_List *l = tiling_g.config->vdesks; l; l = l->next) { + struct _Config_vdesk *newvd; + + vd = l->data; + + if (!vd) + continue; + if (!(newvd = get_vdesk(cfdata->config.vdesks, + vd->x, vd->y, vd->zone_num))) { + change_desk_conf(vd); + continue; + } + + if (newvd->nb_stacks != vd->nb_stacks + || newvd->use_rows != vd->use_rows) { + DBG("number of columns for (%d, %d, %d) changed from %d|%d" + " to %d|%d", + vd->x, vd->y, vd->zone_num, + vd->nb_stacks, vd->use_rows, + newvd->nb_stacks, newvd->use_rows); + change_desk_conf(newvd); + free(vd); + l->data = NULL; + } + } + + for (Eina_List *l = cfdata->config.vdesks; l; l = l->next) { + vd = l->data; + + if (!vd) + continue; + if (!get_vdesk(tiling_g.config->vdesks, + vd->x, vd->y, vd->zone_num)) { + change_desk_conf(vd); + continue; + } + } + + EINA_LIST_FREE(tiling_g.config->vdesks, vd) { + free(vd); + } + + tiling_g.config->vdesks = cfdata->config.vdesks; + cfdata->config.vdesks = NULL; /* we don't want this list to be freed */ + + e_tiling_update_conf(); + + e_config_save_queue(); + + return EINA_TRUE; +} + +E_Config_Dialog * +e_int_config_tiling_module(E_Container *con, + const char *params) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + char buf[PATH_MAX]; + + if (e_config_dialog_find("E", "windows/tiling")) + return NULL; + + v = E_NEW(E_Config_Dialog_View, 1); + + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.apply_cfdata = _basic_apply_data; + v->basic.create_widgets = _basic_create_widgets; + + snprintf(buf, sizeof(buf), "%s/e-module-tiling.edj", + e_module_dir_get(tiling_g.module)); + cfd = e_config_dialog_new(con, + _("Tiling Configuration"), + "E", "windows/tiling", + buf, 0, v, NULL); + return cfd; +} diff --git a/src/modules/tiling/e_mod_tiling.c b/src/modules/tiling/e_mod_tiling.c new file mode 100644 index 000000000..1408fbae3 --- /dev/null +++ b/src/modules/tiling/e_mod_tiling.c @@ -0,0 +1,3917 @@ +#include "e_mod_tiling.h" + +/* types {{{ */ + +#define TILING_OVERLAY_TIMEOUT 5.0 +#define TILING_RESIZE_STEP 5 +#define TILING_POPUP_LAYER 101 +#define TILING_WRAP_SPEED 0.1 + +typedef enum { + TILING_RESIZE, + TILING_MOVE, +} tiling_change_t; + +typedef enum { + INPUT_MODE_NONE, + INPUT_MODE_SWAPPING, + INPUT_MODE_MOVING, + INPUT_MODE_GOING, + INPUT_MODE_TRANSITION, +} tiling_input_mode_t; + +typedef enum { + MOVE_UP, + MOVE_DOWN, + MOVE_LEFT, + MOVE_RIGHT, + + MOVE_COUNT +} tiling_move_t; + +typedef struct geom_t { + int x, y, w, h; +} geom_t; + +typedef struct overlay_t { + E_Popup *popup; + Evas_Object *obj; +} overlay_t; + +typedef struct transition_overlay_t { + overlay_t overlay; + int stack; + char key[4]; + E_Border *bd; +} transition_overlay_t; + +typedef struct Border_Extra { + E_Border *border; + geom_t expected; + struct { + geom_t geom; + unsigned int layer; + E_Stacking stacking; + E_Maximize maximized; + const char *bordername; + } orig; + overlay_t overlay; + char key[4]; +} Border_Extra; + +struct tiling_g tiling_g = { + .module = NULL, + .config = NULL, + .log_domain = -1, + .default_keyhints = "asdfg;lkjh", +}; + +static void +_add_border(E_Border *bd); + +/* }}} */ +/* Globals {{{ */ + +static struct tiling_mod_main_g +{ + char edj_path[PATH_MAX]; + E_Config_DD *config_edd, + *vdesk_edd; + int currently_switching_desktop; + Ecore_X_Window action_input_win; + Ecore_Event_Handler *handler_key, + *handler_border_resize, + *handler_border_move, + *handler_border_add, + *handler_border_remove, + *handler_border_iconify, + *handler_border_uniconify, + *handler_border_stick, + *handler_border_unstick, + *handler_desk_show, + *handler_desk_before_show, + *handler_desk_set, + *handler_container_resize; + E_Border_Hook *pre_border_assign_hook; + + Tiling_Info *tinfo; + Eina_Hash *info_hash; + Eina_Hash *border_extras; + Eina_Hash *overlays; + + E_Action *act_togglefloat, + *act_addstack, + *act_removestack, + *act_tg_stack, + *act_swap, + *act_move, + *act_adjusttransitions, + *act_go; + + int warp_x, + warp_y, + old_warp_x, + old_warp_y, + warp_to_x, + warp_to_y; + Ecore_Timer *warp_timer; + + overlay_t move_overlays[MOVE_COUNT]; + transition_overlay_t *transition_overlay; + Ecore_Timer *action_timer; + E_Border *focused_bd; + void (*action_cb)(E_Border *bd, Border_Extra *extra); + + tiling_input_mode_t input_mode; + char keys[4]; +} _G = { + .input_mode = INPUT_MODE_NONE, +}; + +/* }}} */ +/* Utils {{{ */ + +/* I wonder why noone has implemented the following one yet? */ +static E_Desk * +get_current_desk(void) +{ + E_Manager *m = e_manager_current_get(); + E_Container *c = e_container_current_get(m); + E_Zone *z = e_zone_current_get(c); + + return e_desk_current_get(z); +} + +static Tiling_Info * +_initialize_tinfo(const E_Desk *desk) +{ + Tiling_Info *tinfo; + + tinfo = E_NEW(Tiling_Info, 1); + tinfo->desk = desk; + eina_hash_direct_add(_G.info_hash, &tinfo->desk, tinfo); + + tinfo->conf = get_vdesk(tiling_g.config->vdesks, desk->x, desk->y, + desk->zone->num); + + return tinfo; +} + +static void +check_tinfo(const E_Desk *desk) +{ + if (!_G.tinfo || _G.tinfo->desk != desk) { + _G.tinfo = eina_hash_find(_G.info_hash, &desk); + if (!_G.tinfo) { + /* lazy init */ + _G.tinfo = _initialize_tinfo(desk); + } + if (!_G.tinfo->conf) { + _G.tinfo->conf = get_vdesk(tiling_g.config->vdesks, + desk->x, desk->y, + desk->zone->num); + } + } +} + +static int +is_floating_window(const E_Border *bd) +{ + return EINA_LIST_IS_IN(_G.tinfo->floating_windows, bd); +} + +static int +is_tilable(const E_Border *bd) +{ + if (bd->client.icccm.min_h == bd->client.icccm.max_h + && bd->client.icccm.max_h > 0) + return false; + + if (bd->client.icccm.gravity == ECORE_X_GRAVITY_STATIC) + return false; + + if (!tiling_g.config->tile_dialogs + && ((bd->client.icccm.transient_for != 0) + || (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG))) + return false; + + return true; +} + +static void +change_window_border(E_Border *bd, + const char *bordername) +{ + eina_stringshare_replace(&bd->bordername, bordername); + bd->client.border.changed = true; + bd->changes.border = true; + bd->changed = true; +} + +static int +get_stack(const E_Border *bd) +{ + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if (EINA_LIST_IS_IN(_G.tinfo->stacks[i], bd)) + return i; + } + return -1; +} + +static int +get_stack_count(void) +{ + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if (!_G.tinfo->stacks[i]) + return i; + } + return TILING_MAX_STACKS; +} + +static int +get_window_count(void) +{ + int res = 0; + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if (!_G.tinfo->stacks[i]) + break; + res += eina_list_count(_G.tinfo->stacks[i]); + } + return res; +} + +static int +get_transition_count(void) +{ + int res = 0; + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if (!_G.tinfo->stacks[i]) + break; + res += eina_list_count(_G.tinfo->stacks[i]); + } + if (_G.tinfo->stacks[0]) + res--; + return res; +} + +static void +_theme_edje_object_set_aux(Evas_Object *obj, const char *group) +{ + if (!e_theme_edje_object_set(obj, "base/theme/modules/tiling", + group)) { + edje_object_file_set(obj, _G.edj_path, group); + } +} +#define _theme_edje_object_set(_obj, _group) \ + if (e_config->use_composite) \ + _theme_edje_object_set_aux(_obj, _group"/composite"); \ + else \ + _theme_edje_object_set_aux(_obj, _group); + +static Eina_Bool +_info_hash_update(const Eina_Hash *hash, const void *key, + void *data, void *fdata) +{ + Tiling_Info *tinfo = data; + + if (tinfo->desk) { + tinfo->conf = get_vdesk(tiling_g.config->vdesks, + tinfo->desk->x, tinfo->desk->y, + tinfo->desk->zone->num); + } else { + tinfo->conf = NULL; + } + + return true; +} + +void +e_tiling_update_conf(void) +{ + eina_hash_foreach(_G.info_hash, _info_hash_update, NULL); +} + +static void +_e_border_move_resize(E_Border *bd, + int x, + int y, + int w, + int h) +{ + DBG("%p -> %dx%d+%d+%d", bd, w, h, x, y); + e_border_move_resize(bd, x, y, w, h); +} + +static void +_e_border_move(E_Border *bd, + int x, + int y) +{ + DBG("%p -> +%d+%d", bd, x, y); + e_border_move(bd, x, y); +} + +static void +_e_border_resize(E_Border *bd, + int w, + int h) +{ + DBG("%p -> %dx%d", bd, w, h); + e_border_resize(bd, w, h); +} + +static void +_e_border_maximize(E_Border *bd, E_Maximize max) +{ + DBG("%p -> %s", bd, + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_NONE ? "NONE" : + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL ? "VERTICAL" : + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL ? "HORIZONTAL" : + "BOTH"); + DBG("new_client:%s, bd->maximized=%x", + bd->new_client? "true": "false", + bd->maximized); + e_border_maximize(bd, max); +} + +static void +_e_border_unmaximize(E_Border *bd, E_Maximize max) +{ + DBG("%p -> %s", bd, + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_NONE ? "NONE" : + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL ? "VERTICAL" : + (max & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL ? "HORIZONTAL" : + "BOTH"); + e_border_unmaximize(bd, max); +} + +static void +_restore_border(E_Border *bd) +{ + Border_Extra *extra; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + _e_border_unmaximize(bd, E_MAXIMIZE_BOTH); + _e_border_move_resize(bd, + extra->orig.geom.x, + extra->orig.geom.y, + extra->orig.geom.w, + extra->orig.geom.h); + e_border_layer_set(bd, extra->orig.layer); + e_hints_window_stacking_set(bd, extra->orig.stacking); + if (extra->orig.maximized) { + e_border_maximize(bd, extra->orig.maximized); + bd->maximized = extra->orig.maximized; + } + + + change_window_border(bd, extra->orig.bordername); +} + +static Border_Extra * +_get_or_create_border_extra(E_Border *bd) +{ + Border_Extra *extra; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + extra = E_NEW(Border_Extra, 1); + *extra = (Border_Extra) { + .border = bd, + .expected = { + .x = bd->x, + .y = bd->y, + .w = bd->w, + .h = bd->h, + }, + .orig = { + .geom = { + .x = bd->x, + .y = bd->y, + .w = bd->w, + .h = bd->h, + }, + .layer = bd->layer, + .stacking = bd->client.netwm.state.stacking, + .maximized = bd->maximized, + .bordername = eina_stringshare_add(bd->bordername), + }, + }; + eina_hash_direct_add(_G.border_extras, &extra->border, extra); + } else { + extra->expected = (geom_t) { + .x = bd->x, + .y = bd->y, + .w = bd->w, + .h = bd->h, + }; + } + + return extra; +} + +/* }}} */ +/* Overlays {{{*/ + +static void +_overlays_free_cb(void *data) +{ + Border_Extra *extra = data; + + if (extra->overlay.obj) { + evas_object_del(extra->overlay.obj); + extra->overlay.obj = NULL; + } + if (extra->overlay.popup) { + e_object_del(E_OBJECT(extra->overlay.popup)); + extra->overlay.popup = NULL; + } + + extra->key[0] = '\0'; +} + +static void +end_special_input(void) +{ + if (_G.input_mode == INPUT_MODE_NONE) + return; + + if (_G.overlays) { + eina_hash_free(_G.overlays); + _G.overlays = NULL; + } + + if (_G.handler_key) { + ecore_event_handler_del(_G.handler_key); + _G.handler_key = NULL; + } + if (_G.action_input_win) { + e_grabinput_release(_G.action_input_win, _G.action_input_win); + ecore_x_window_free(_G.action_input_win); + _G.action_input_win = 0; + } + if (_G.action_timer) { + ecore_timer_del(_G.action_timer); + _G.action_timer = NULL; + } + + _G.focused_bd = NULL; + _G.action_cb = NULL; + + switch(_G.input_mode) { + case INPUT_MODE_MOVING: + for (int i = 0; i < MOVE_COUNT; i++) { + overlay_t *overlay = &_G.move_overlays[i]; + + if (overlay->obj) { + evas_object_del(overlay->obj); + overlay->obj = NULL; + } + if (overlay->popup) { + e_object_del(E_OBJECT(overlay->popup)); + overlay->popup = NULL; + } + } + break; + case INPUT_MODE_TRANSITION: + if (_G.transition_overlay) { + if (_G.transition_overlay->overlay.obj) { + evas_object_del(_G.transition_overlay->overlay.obj); + } + if (_G.transition_overlay->overlay.popup) { + e_object_del(E_OBJECT(_G.transition_overlay->overlay.popup)); + } + E_FREE(_G.transition_overlay); + _G.transition_overlay = NULL; + } + break; + default: + break; + } + + _G.input_mode = INPUT_MODE_NONE; +} + +static Eina_Bool +overlay_key_down(void *data, + int type, + void *event) +{ + Ecore_Event_Key *ev = event; + Border_Extra *extra; + + if (ev->event_window != _G.action_input_win) + return ECORE_CALLBACK_PASS_ON; + + if (strcmp(ev->key, "Return") == 0) + goto stop; + if (strcmp(ev->key, "Escape") == 0) + goto stop; + if (strcmp(ev->key, "Backspace") == 0) { + char *key = _G.keys; + + while (*key) + key++; + *key = '\0'; + return ECORE_CALLBACK_RENEW; + } + + if (ev->key[0] && !ev->key[1] && strchr(tiling_g.config->keyhints, + ev->key[1])) { + char *key = _G.keys; + + while (*key) + key++; + *key++ = ev->key[0]; + *key = '\0'; + + extra = eina_hash_find(_G.overlays, _G.keys); + if (extra) { + _G.action_cb(_G.focused_bd, extra); + } else { + return ECORE_CALLBACK_RENEW; + } + } + +stop: + end_special_input(); + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_timeout_cb(void *data) +{ + end_special_input(); + return ECORE_CALLBACK_CANCEL; +} + +static void +_do_overlay(E_Border *focused_bd, + void (*action_cb)(E_Border *, Border_Extra *), + tiling_input_mode_t input_mode) +{ + Ecore_X_Window parent; + int nb_win; + int hints_len; + int key_len; + int n = 0; + int nmax; + + end_special_input(); + + nb_win = get_window_count(); + if (nb_win < 2) { + return; + } + + _G.input_mode = input_mode; + + _G.focused_bd = focused_bd; + _G.action_cb = action_cb; + + _G.overlays = eina_hash_string_small_new(_overlays_free_cb); + + hints_len = strlen(tiling_g.config->keyhints); + key_len = 1; + nmax = hints_len; + if (hints_len < nb_win) { + key_len = 2; + nmax *= hints_len; + if (hints_len * hints_len < nb_win) { + key_len = 3; + nmax *= hints_len; + } + } + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + Eina_List *l; + E_Border *bd; + + if (!_G.tinfo->stacks[i]) + break; + EINA_LIST_FOREACH(_G.tinfo->stacks[i], l, bd) { + if (bd != focused_bd && n < nmax) { + Border_Extra *extra; + Evas_Coord ew, eh; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + + extra->overlay.popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!extra->overlay.popup) + continue; + + e_popup_layer_set(extra->overlay.popup, TILING_POPUP_LAYER); + extra->overlay.obj = + edje_object_add(extra->overlay.popup->evas); + e_theme_edje_object_set(extra->overlay.obj, + "base/theme/borders", + "e/widgets/border/default/resize"); + + switch (key_len) { + case 1: + extra->key[0] = tiling_g.config->keyhints[n]; + extra->key[1] = '\0'; + break; + case 2: + extra->key[0] = tiling_g.config->keyhints[n / hints_len]; + extra->key[1] = tiling_g.config->keyhints[n % hints_len]; + extra->key[2] = '\0'; + break; + case 3: + extra->key[0] = tiling_g.config->keyhints[n / hints_len / hints_len]; + extra->key[0] = tiling_g.config->keyhints[n / hints_len]; + extra->key[1] = tiling_g.config->keyhints[n % hints_len]; + extra->key[2] = '\0'; + break; + } + n++; + + eina_hash_add(_G.overlays, extra->key, extra); + edje_object_part_text_set(extra->overlay.obj, + "e.text.label", + extra->key); + edje_object_size_min_calc(extra->overlay.obj, &ew, &eh); + evas_object_move(extra->overlay.obj, 0, 0); + evas_object_resize(extra->overlay.obj, ew, eh); + evas_object_show(extra->overlay.obj); + e_popup_edje_bg_object_set(extra->overlay.popup, + extra->overlay.obj); + + evas_object_show(extra->overlay.obj); + e_popup_show(extra->overlay.popup); + + e_popup_move_resize(extra->overlay.popup, + (bd->x - extra->overlay.popup->zone->x) + + ((bd->w - ew) / 2), + (bd->y - extra->overlay.popup->zone->y) + + ((bd->h - eh) / 2), + ew, eh); + + e_popup_show(extra->overlay.popup); + } + } + } + + /* Get input */ + parent = _G.tinfo->desk->zone->container->win; + _G.action_input_win = ecore_x_window_input_new(parent, 0, 0, 1, 1); + if (!_G.action_input_win) { + end_special_input(); + return; + } + + ecore_x_window_show(_G.action_input_win); + if (!e_grabinput_get(_G.action_input_win, 0, _G.action_input_win)) { + end_special_input(); + return; + } + _G.action_timer = ecore_timer_add(TILING_OVERLAY_TIMEOUT, + _timeout_cb, NULL); + + _G.keys[0] = '\0'; + _G.handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + overlay_key_down, NULL); +} + +/* }}} */ +/* Reorganize Stacks {{{*/ + +static void +_reorganize_stack(int stack) +{ + if (stack < 0 || stack >= TILING_MAX_STACKS + || !_G.tinfo->stacks[stack]) + return; + + if (_G.tinfo->stacks[stack]->next) { + int zx, zy, zw, zh, i = 0, count; + + e_zone_useful_geometry_get(_G.tinfo->desk->zone, &zx, &zy, &zw, &zh); + + count = eina_list_count(_G.tinfo->stacks[stack]); + + if (_G.tinfo->conf->use_rows) { + int y, w, h, cw; + + y = _G.tinfo->pos[stack]; + cw = 0; + w = zw / count; + h = _G.tinfo->size[stack]; + + for (Eina_List *l = _G.tinfo->stacks[stack]; l; l = l->next, i++) { + E_Border *bd = l->data; + Border_Extra *extra; + int d = (i * 2 * zw) % count + - (2 * cw) % count; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + + if ((bd->maximized & E_MAXIMIZE_HORIZONTAL) && count != 1) { + _e_border_unmaximize(bd, E_MAXIMIZE_HORIZONTAL); + } + /* let's use a bresenham here */ + + extra->expected.x = cw + zx; + extra->expected.y = y; + extra->expected.w = w + d; + extra->expected.h = h; + cw += extra->expected.w; + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + } else { + int x, w, h, ch; + + x = _G.tinfo->pos[stack]; + ch = 0; + w = _G.tinfo->size[stack]; + h = zh / count; + + for (Eina_List *l = _G.tinfo->stacks[stack]; l; l = l->next, i++) { + E_Border *bd = l->data; + Border_Extra *extra; + int d = (i * 2 * zh) % count + - (2 * ch) % count; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + + if ((bd->maximized & E_MAXIMIZE_VERTICAL) && count != 1) { + _e_border_unmaximize(bd, E_MAXIMIZE_VERTICAL); + } + /* let's use a bresenham here */ + + extra->expected.x = x; + extra->expected.y = ch + zy; + extra->expected.w = w; + extra->expected.h = h + d; + ch += extra->expected.h; + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + } + } else { + Border_Extra *extra; + E_Border *bd = _G.tinfo->stacks[stack]->data; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + if (_G.tinfo->conf->use_rows) { + int x, w; + + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + &x, NULL, &w, NULL); + + extra->expected.x = x; + extra->expected.y = _G.tinfo->pos[stack]; + extra->expected.w = w; + extra->expected.h = _G.tinfo->size[stack]; + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_HORIZONTAL); + } else { + int y, h; + + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + NULL, &y, NULL, &h); + + extra->expected.x = _G.tinfo->pos[stack]; + extra->expected.y = y; + extra->expected.w = _G.tinfo->size[stack]; + extra->expected.h = h; + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_VERTICAL); + } + } +} + +static void +_move_resize_stack(int stack, int delta_pos, int delta_size) +{ + Eina_List *list = _G.tinfo->stacks[stack]; + + for (Eina_List *l = list; l; l = l->next) { + E_Border *bd = l->data; + Border_Extra *extra; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + + if (_G.tinfo->conf->use_rows) { + extra->expected.y += delta_pos; + extra->expected.h += delta_size; + } else { + extra->expected.x += delta_pos; + extra->expected.w += delta_size; + } + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + + _G.tinfo->pos[stack] += delta_pos; + _G.tinfo->size[stack] += delta_size; +} + +static void +_set_stack_geometry(int stack, int pos, int size) +{ + for (Eina_List *l = _G.tinfo->stacks[stack]; l; l = l->next) { + E_Border *bd = l->data; + Border_Extra *extra; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + DBG("expected: %dx%d+%d+%d (%p)", + extra->expected.w, + extra->expected.h, + extra->expected.x, + extra->expected.y, + bd); + + if (_G.tinfo->conf->use_rows) { + extra->expected.y = pos; + extra->expected.h = size; + + if (bd->maximized) { + if (l->next && (bd->maximized & E_MAXIMIZE_HORIZONTAL)) + _e_border_unmaximize(bd, E_MAXIMIZE_HORIZONTAL); + if (_G.tinfo->stacks[1] && (bd->maximized & E_MAXIMIZE_VERTICAL)) + _e_border_unmaximize(bd, E_MAXIMIZE_VERTICAL); + } + } else { + extra->expected.x = pos; + extra->expected.w = size; + + if (bd->maximized) { + if (l->next && (bd->maximized & E_MAXIMIZE_VERTICAL)) + _e_border_unmaximize(bd, E_MAXIMIZE_VERTICAL); + if (_G.tinfo->stacks[1] && (bd->maximized & E_MAXIMIZE_HORIZONTAL)) + _e_border_unmaximize(bd, E_MAXIMIZE_HORIZONTAL); + } + } + + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + _G.tinfo->pos[stack] = pos; + _G.tinfo->size[stack] = size; +} + +static void +_add_stack(void) +{ + int nb_borders; + + if (_G.tinfo->conf->nb_stacks == TILING_MAX_STACKS) + return; + + _G.tinfo->conf->nb_stacks++; + + if (_G.tinfo->conf->nb_stacks == 1) { + for (Eina_List *l = e_border_focus_stack_get(); l; l = l->next) { + E_Border *bd; + + bd = l->data; + if (bd->desk == _G.tinfo->desk) + _add_border(bd); + } + } + nb_borders = get_window_count(); + if (_G.tinfo->stacks[_G.tinfo->conf->nb_stacks - 2] + && nb_borders >= _G.tinfo->conf->nb_stacks) + { + int nb_stacks = _G.tinfo->conf->nb_stacks - 1; + int pos, s; + /* Add stack */ + + if (_G.tinfo->conf->use_rows) + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + NULL, &pos, NULL, &s); + else + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + &pos, NULL, &s, NULL); + + for (int i = 0; i <= nb_stacks; i++) { + int size = 0; + + size = s / (nb_stacks + 1 - i); + + _set_stack_geometry(i, pos, size); + + s -= size; + pos += size; + } + for (int i = nb_stacks - 1; i >= 0; i--) { + if (eina_list_count(_G.tinfo->stacks[i]) == 1) { + _G.tinfo->stacks[i+1] = _G.tinfo->stacks[i]; + _reorganize_stack(i+1); + } else { + E_Border *bd = eina_list_last(_G.tinfo->stacks[i])->data; + + EINA_LIST_REMOVE(_G.tinfo->stacks[i], bd); + _reorganize_stack(i); + + _G.tinfo->stacks[i+1] = NULL; + EINA_LIST_APPEND(_G.tinfo->stacks[i+1], bd); + _reorganize_stack(i+1); + return; + } + } + } +} + +static void +_remove_stack(void) +{ + if (!_G.tinfo->conf->nb_stacks) + return; + + _G.tinfo->conf->nb_stacks--; + + if (!_G.tinfo->conf->nb_stacks) { + for (int i = 0; i < TILING_MAX_STACKS; i++) { + for (Eina_List *l = _G.tinfo->stacks[i]; l; l = l->next) { + E_Border *bd = l->data; + + _restore_border(bd); + } + eina_list_free(_G.tinfo->stacks[i]); + _G.tinfo->stacks[i] = NULL; + } + e_place_zone_region_smart_cleanup(_G.tinfo->desk->zone); + } else { + int nb_stacks = _G.tinfo->conf->nb_stacks; + int stack = _G.tinfo->conf->nb_stacks; + int pos, s; + + if (_G.tinfo->stacks[stack]) { + _G.tinfo->stacks[stack-1] = eina_list_merge( + _G.tinfo->stacks[stack-1], _G.tinfo->stacks[stack]); + _reorganize_stack(stack-1); + } + + if (_G.tinfo->conf->use_rows) { + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + NULL, &pos, NULL, &s); + } else { + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + &pos, NULL, &s, NULL); + } + for (int i = 0; i < nb_stacks; i++) { + int size = 0; + + size = s / (nb_stacks - i); + + _set_stack_geometry(i, pos, size); + + s -= size; + pos += size; + } + } +} + +static void +_toggle_rows_cols(void) +{ +#if 0 + Eina_List *wins = NULL; + E_Border *bd; + + _G.tinfo->conf->use_rows = !_G.tinfo->conf->use_rows; + for (int i = 0; i < TILING_MAX_STACKS; i++) { + EINA_LIST_FREE(_G.tinfo->stacks[i], bd) { + EINA_LIST_APPEND(wins, bd); + _restore_border(bd); + } + _G.tinfo->stacks[i] = NULL; + _G.tinfo->pos[i] = 0; + _G.tinfo->size[i] = 0; + } + + DBG("reinsert (use_rows: %s)", + _G.tinfo->conf->use_rows ? "true":"false"); + + EINA_LIST_FREE(wins, bd) { + _add_border(bd); + } +#else + int nb_stacks = _G.tinfo->conf->nb_stacks; + int pos, s; + + _G.tinfo->conf->use_rows = !_G.tinfo->conf->use_rows; + + if (_G.tinfo->conf->use_rows) + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + NULL, &pos, NULL, &s); + else + e_zone_useful_geometry_get(_G.tinfo->desk->zone, + &pos, NULL, &s, NULL); + + for (int i = 0; i < nb_stacks; i++) { + int size = 0; + + size = s / (nb_stacks - i); + + _set_stack_geometry(i, pos, size); + + s -= size; + pos += size; + } + for (int i = 0; i < nb_stacks; i++) { + _reorganize_stack(i); + } +#endif +} + +void +change_desk_conf(struct _Config_vdesk *newconf) +{ + E_Manager *m; + E_Container *c; + E_Zone *z; + E_Desk *d; + int old_nb_stacks = 0, + new_nb_stacks = newconf->nb_stacks; + + m = e_manager_current_get(); + if (!m) return; + c = e_container_current_get(m); + if (!c) return; + z = e_container_zone_number_get(c, newconf->zone_num); + if (!z) return; + d = e_desk_at_xy_get(z, newconf->x, newconf->y); + if (!d) return; + + check_tinfo(d); + if (_G.tinfo->conf) { + old_nb_stacks = _G.tinfo->conf->nb_stacks; + if (_G.tinfo->conf->use_rows != newconf->use_rows) { + _G.tinfo->conf = newconf; + _G.tinfo->conf->use_rows = !_G.tinfo->conf->use_rows; + _toggle_rows_cols(); + return; + } + } else { + newconf->nb_stacks = 0; + } + _G.tinfo->conf = newconf; + _G.tinfo->conf->nb_stacks = old_nb_stacks; + + if (new_nb_stacks == old_nb_stacks) + return; + + if (new_nb_stacks == 0) { + for (int i = 0; i < TILING_MAX_STACKS; i++) { + for (Eina_List *l = _G.tinfo->stacks[i]; l; l = l->next) { + E_Border *bd = l->data; + + _restore_border(bd); + } + eina_list_free(_G.tinfo->stacks[i]); + _G.tinfo->stacks[i] = NULL; + } + e_place_zone_region_smart_cleanup(z); + } else if (new_nb_stacks > old_nb_stacks) { + for (int i = new_nb_stacks; i > old_nb_stacks; i--) { + _add_stack(); + } + } else { + for (int i = new_nb_stacks; i < old_nb_stacks; i++) { + _remove_stack(); + } + } + _G.tinfo->conf->nb_stacks = new_nb_stacks; +} + +static void +_e_mod_action_add_stack_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk = get_current_desk(); + + end_special_input(); + + check_tinfo(desk); + + _add_stack(); + + e_config_save_queue(); +} + +static void +_e_mod_action_remove_stack_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk = get_current_desk(); + + end_special_input(); + + check_tinfo(desk); + + _remove_stack(); + + e_config_save_queue(); +} + +static void +_e_mod_action_tg_stack_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk = get_current_desk(); + + end_special_input(); + + check_tinfo(desk); + + _toggle_rows_cols(); + + e_config_save_queue(); +} + + +/* }}} */ +/* Reorganize windows {{{*/ + +static void +_add_border(E_Border *bd) +{ + Border_Extra *extra; + int stack; + + if (!bd) { + return; + } + if (is_floating_window(bd)) { + return; + } + if (!is_tilable(bd)) { + return; + } + if (bd->fullscreen) { + return; + } + + if (!_G.tinfo || !_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + extra = _get_or_create_border_extra(bd); + + /* Stack tiled window below so that winlist doesn't mix up stacking */ + e_border_layer_set(bd, 75); + e_hints_window_stacking_set(bd, E_STACKING_BELOW); + + DBG("adding %p", bd); + + if (_G.tinfo->stacks[0]) { + DBG("got stack 0"); + if (_G.tinfo->stacks[_G.tinfo->conf->nb_stacks - 1]) { + DBG("using last stack"); + stack = _G.tinfo->conf->nb_stacks - 1; + + if (!_G.tinfo->stacks[stack]->next) { + _e_border_unmaximize(_G.tinfo->stacks[stack]->data, + E_MAXIMIZE_BOTH); + } + EINA_LIST_APPEND(_G.tinfo->stacks[stack], bd); + _reorganize_stack(stack); + if (bd->maximized) + _e_border_unmaximize(bd, E_MAXIMIZE_BOTH); + } else { + /* Add stack */ + int nb_stacks = get_stack_count(); + int x, y, w, h; + int pos, s, size = 0; + + DBG("add stack"); + + e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); + + if (_G.tinfo->conf->use_rows) { + pos = y; + s = h; + } else { + pos = x; + s = w; + } + + EINA_LIST_APPEND(_G.tinfo->stacks[nb_stacks], bd); + + for (int i = 0; i < nb_stacks; i++) { + + size = s / (nb_stacks + 1 - i); + + _set_stack_geometry(i, pos, size); + + s -= size; + pos += size; + } + + _G.tinfo->pos[nb_stacks] = pos; + _G.tinfo->size[nb_stacks] = size; + if (_G.tinfo->conf->use_rows) { + extra->expected.x = x; + extra->expected.y = pos; + extra->expected.w = w; + extra->expected.h = size; + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | + E_MAXIMIZE_HORIZONTAL); + } else { + extra->expected.x = pos; + extra->expected.y = y; + extra->expected.w = size; + extra->expected.h = h; + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | + E_MAXIMIZE_VERTICAL); + } + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + + stack = nb_stacks; + } + } else { + DBG("lonely window"); + e_zone_useful_geometry_get(bd->zone, + &extra->expected.x, + &extra->expected.y, + &extra->expected.w, + &extra->expected.h); + + if (bd->maximized & E_MAXIMIZE_BOTH) + _e_border_unmaximize(bd, E_MAXIMIZE_BOTH); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH); + EINA_LIST_APPEND(_G.tinfo->stacks[0], bd); + if (_G.tinfo->conf->use_rows) { + e_zone_useful_geometry_get(bd->zone, + NULL, &_G.tinfo->pos[0], + NULL, &_G.tinfo->size[0]); + } else { + e_zone_useful_geometry_get(bd->zone, + &_G.tinfo->pos[0], NULL, + &_G.tinfo->size[0], NULL); + } + stack = 0; + } + DBG("expected: %dx%d+%d+%d (%p)", + extra->expected.w, + extra->expected.h, + extra->expected.x, + extra->expected.y, + bd); +} + +static void +_remove_border(E_Border *bd) +{ + int stack; + int nb_stacks; + + nb_stacks = get_stack_count(); + + stack = get_stack(bd); + if (stack < 0) + return; + + DBG("removing %p (%d%c)", bd, stack, _G.tinfo->conf->use_rows? 'r':'c'); + + EINA_LIST_REMOVE(_G.tinfo->stacks[stack], bd); + eina_hash_del(_G.border_extras, bd, NULL); + + if (_G.tinfo->stacks[stack]) { + _reorganize_stack(stack); + } else { + int nb_borders = get_window_count(); + + if (nb_stacks > nb_borders) { + int pos, s; + /* Remove stack */ + + nb_stacks--; + + for (int i = stack; i < nb_stacks; i++) { + _G.tinfo->stacks[i] = _G.tinfo->stacks[i+1]; + } + _G.tinfo->stacks[nb_stacks] = NULL; + if (_G.tinfo->conf->use_rows) { + e_zone_useful_geometry_get(bd->zone, + NULL, &pos, NULL, &s); + } else { + e_zone_useful_geometry_get(bd->zone, + &pos, NULL, &s, NULL); + } + for (int i = 0; i < nb_stacks; i++) { + int size; + + size = s / (nb_stacks - i); + + _set_stack_geometry(i, pos, size); + + s -= size; + pos += size; + } + } else { + for (int i = stack+1; i < nb_stacks; i++) { + if (eina_list_count(_G.tinfo->stacks[i]) > 1) { + for (int j = stack; j < i - 1; j++) { + _G.tinfo->stacks[j] = _G.tinfo->stacks[j+1]; + _reorganize_stack(j); + } + bd = _G.tinfo->stacks[i]->data; + EINA_LIST_REMOVE(_G.tinfo->stacks[i], bd); + _reorganize_stack(i); + + _G.tinfo->stacks[i-1] = NULL; + EINA_LIST_APPEND(_G.tinfo->stacks[i-1], bd); + _reorganize_stack(i-1); + return; + } + } + for (int i = stack-1; i >= 0; i--) { + if (eina_list_count(_G.tinfo->stacks[i]) == 1) { + _G.tinfo->stacks[i+1] = _G.tinfo->stacks[i]; + _reorganize_stack(i+1); + } else { + bd = eina_list_last(_G.tinfo->stacks[i])->data; + EINA_LIST_REMOVE(_G.tinfo->stacks[i], bd); + _reorganize_stack(i); + + _G.tinfo->stacks[i+1] = NULL; + EINA_LIST_APPEND(_G.tinfo->stacks[i+1], bd); + _reorganize_stack(i+1); + return; + } + } + } + } +} + +static void +_move_resize_border_stack(E_Border *bd, Border_Extra *extra, + int stack, tiling_change_t change) +{ +#define _MOVE_RESIZE_BORDER_STACK(_pos, _size) \ + if (change == TILING_RESIZE) { \ + if (stack == TILING_MAX_STACKS || !_G.tinfo->stacks[stack + 1]) { \ + /* You're not allowed to resize */ \ + bd->_size = extra->expected._size; \ + } else { \ + int delta = bd->_size - extra->expected._size; \ + \ + if (delta + 1 > _G.tinfo->size[stack + 1]) \ + delta = _G.tinfo->size[stack + 1] - 1; \ + \ + _move_resize_stack(stack, 0, delta); \ + _move_resize_stack(stack + 1, delta, -delta); \ + extra->expected._size = bd->_size; \ + } \ + } else { \ + if (stack == 0) { \ + /* You're not allowed to move */ \ + bd->_pos = extra->expected._pos; \ + } else { \ + int delta = bd->_pos - extra->expected._pos; \ + \ + if (delta + 1 > _G.tinfo->size[stack - 1]) \ + delta = _G.tinfo->size[stack - 1] - 1; \ + \ + _move_resize_stack(stack, delta, -delta); \ + _move_resize_stack(stack - 1, 0, delta); \ + extra->expected._pos = bd->_pos; \ + } \ + } + if (_G.tinfo->conf->use_rows) { + _MOVE_RESIZE_BORDER_STACK(y, h) + } else { + _MOVE_RESIZE_BORDER_STACK(x, w) + } +#undef _MOVE_RESIZE_BORDER_STACK +} + +static void +_move_resize_border_in_stack(E_Border *bd, Border_Extra *extra, + int stack, tiling_change_t change) +{ + Eina_List *l; + + l = eina_list_data_find_list(_G.tinfo->stacks[stack], bd); + if (!l) { + ERR("unable to bd %p in stack %d", bd, stack); + return; + } + + switch (change) { + case TILING_RESIZE: + if (!l->next) { + if (l->prev) { + E_Border *prevbd = l->prev->data; + Border_Extra *prevextra; + + prevextra = eina_hash_find(_G.border_extras, &prevbd); + if (!prevextra) { + ERR("No extra for %p", prevbd); + return; + } + + if (_G.tinfo->conf->use_rows) { + int delta; + + delta = bd->w - extra->expected.w; + prevextra->expected.w -= delta; + extra->expected.x -= delta; + extra->expected.w = bd->w; + } else { + int delta; + + delta = bd->h - extra->expected.h; + prevextra->expected.h -= delta; + extra->expected.y -= delta; + extra->expected.h = bd->h; + } + + _e_border_resize(prevbd, + prevextra->expected.w, + prevextra->expected.h); + _e_border_move(bd, + extra->expected.x, + extra->expected.y); + } else { + /* You're not allowed to resize */ + _e_border_resize(bd, + extra->expected.w, + extra->expected.h); + } + } else { + E_Border *nextbd = l->next->data; + Border_Extra *nextextra; + + nextextra = eina_hash_find(_G.border_extras, &nextbd); + if (!nextextra) { + ERR("No extra for %p", nextbd); + return; + } + + if (_G.tinfo->conf->use_rows) { + int min_width = MAX(nextbd->client.icccm.base_w, 1); + int delta; + + delta = bd->w - extra->expected.w; + if (nextextra->expected.w - delta < min_width) + delta = nextextra->expected.w - min_width; + + nextextra->expected.x += delta; + nextextra->expected.w -= delta; + + extra->expected.w += delta; + } else { + int min_height = MAX(nextbd->client.icccm.base_h, 1); + int delta; + + delta = bd->h - extra->expected.h; + if (nextextra->expected.h - delta < min_height) + delta = nextextra->expected.h - min_height; + + nextextra->expected.y += delta; + nextextra->expected.h -= delta; + + extra->expected.h += delta; + } + + _e_border_move_resize(nextbd, + nextextra->expected.x, + nextextra->expected.y, + nextextra->expected.w, + nextextra->expected.h); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + break; + case TILING_MOVE: + if (!l->prev) { + /* You're not allowed to move */ + if (_G.tinfo->conf->use_rows) { + bd->x = extra->expected.x; + } else { + bd->y = extra->expected.y; + } + _e_border_move(bd, + extra->expected.x, + extra->expected.y); + DBG("trying to move %p, but !l->prev", bd); + } else { + E_Border *prevbd = l->prev->data; + Border_Extra *prevextra; + + prevextra = eina_hash_find(_G.border_extras, &prevbd); + if (!prevextra) { + ERR("No extra for %p", prevbd); + return; + } + + if (_G.tinfo->conf->use_rows) { + int delta = bd->x - extra->expected.x; + int min_width = MAX(prevbd->client.icccm.base_w, 1); + + if (prevextra->expected.w - delta < min_width) + delta = prevextra->expected.w - min_width; + + prevextra->expected.w += delta; + + extra->expected.x += delta; + extra->expected.w -= delta; + } else { + int delta = bd->y - extra->expected.y; + int min_height = MAX(prevbd->client.icccm.base_h, 1); + + if (prevextra->expected.h - delta < min_height) + delta = prevextra->expected.h - min_height; + + prevextra->expected.h += delta; + + extra->expected.y += delta; + extra->expected.h -= delta; + } + + _e_border_resize(prevbd, + prevextra->expected.w, + prevextra->expected.h); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + } + break; + default: + ERR("invalid tiling change: %d", change); + } +} + +/* }}} */ +/* Toggle Floating {{{ */ + +static void +toggle_floating(E_Border *bd) +{ + if (!bd) + return; + check_tinfo(bd->desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) + return; + + if (EINA_LIST_IS_IN(_G.tinfo->floating_windows, bd)) { + EINA_LIST_REMOVE(_G.tinfo->floating_windows, bd); + + _add_border(bd); + } else { + _remove_border(bd); + _restore_border(bd); + } +} + +static void +_e_mod_action_toggle_floating_cb(E_Object *obj, + const char *params) +{ + end_special_input(); + + toggle_floating(e_border_focused_get()); +} + +/* }}} */ +/* {{{ Swap */ + +static void +_action_swap(E_Border *bd_1, + Border_Extra *extra_2) +{ + Border_Extra *extra_1; + E_Border *bd_2 = extra_2->border; + Eina_List *l_1 = NULL, + *l_2 = NULL; + geom_t gt; + unsigned int bd_2_maximized; + + extra_1 = eina_hash_find(_G.border_extras, &bd_1); + if (!extra_1) { + ERR("No extra for %p", bd_1); + return; + } + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if ((l_1 = eina_list_data_find_list(_G.tinfo->stacks[i], bd_1))) { + break; + } + } + for (int i = 0; i < TILING_MAX_STACKS; i++) { + if ((l_2 = eina_list_data_find_list(_G.tinfo->stacks[i], bd_2))) { + break; + } + } + + if (!l_1 || !l_2) { + return; + } + + l_1->data = bd_2; + l_2->data = bd_1; + + gt = extra_2->expected; + extra_2->expected = extra_1->expected; + extra_1->expected = gt; + + bd_2_maximized = bd_2->maximized; + if (bd_2->maximized) + _e_border_unmaximize(bd_2, E_MAXIMIZE_BOTH); + if (bd_1->maximized) { + _e_border_unmaximize(bd_1, E_MAXIMIZE_BOTH); + _e_border_maximize(bd_2, bd_1->maximized); + } + if (bd_2_maximized) { + _e_border_maximize(bd_1, bd_2_maximized); + } + _e_border_move_resize(bd_1, + extra_1->expected.x, + extra_1->expected.y, + extra_1->expected.w, + extra_1->expected.h); + _e_border_move_resize(bd_2, + extra_2->expected.x, + extra_2->expected.y, + extra_2->expected.w, + extra_2->expected.h); +} + +static void +_e_mod_action_swap_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk; + E_Border *focused_bd; + + desk = get_current_desk(); + if (!desk) + return; + + focused_bd = e_border_focused_get(); + if (!focused_bd || focused_bd->desk != desk) + return; + + check_tinfo(desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + _do_overlay(focused_bd, _action_swap, INPUT_MODE_SWAPPING); +} + +/* }}} */ +/* Move {{{*/ + +static void +_check_moving_anims(const E_Border *bd, const Border_Extra *extra, int stack) +{ + Eina_List *l = NULL; + overlay_t *overlay; + int nb_stacks = get_stack_count(); + + if (stack < 0) { + stack = get_stack(bd); + if (stack < 0) + return; + } + if (!extra) { + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + } + l = eina_list_data_find_list(_G.tinfo->stacks[stack], bd); + if (!l) + return; + + /* move left */ + overlay = &_G.move_overlays[MOVE_LEFT]; + if ((!_G.tinfo->conf->use_rows && stack > 0) + || (_G.tinfo->conf->use_rows && l->prev)) { + if (overlay->popup) { + Evas_Coord ew, eh; + + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_move(_G.move_overlays[MOVE_LEFT].popup, + extra->expected.x - ew/2, + extra->expected.y + extra->expected.h/2 - eh/2); + } else { + Evas_Coord ew, eh; + + overlay->popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!overlay->popup) + return; + + e_popup_layer_set(overlay->popup, TILING_POPUP_LAYER); + overlay->obj = edje_object_add(overlay->popup->evas); + _theme_edje_object_set(overlay->obj, + "modules/tiling/move/left"); + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_edje_bg_object_set(overlay->popup, + overlay->obj); + evas_object_show(overlay->obj); + e_popup_move_resize(overlay->popup, + extra->expected.x - ew/2 + - overlay->popup->zone->x, + extra->expected.y + extra->expected.h/2 + - eh/2 + - overlay->popup->zone->y, + ew, + eh); + evas_object_resize(overlay->obj, ew, eh); + + e_popup_show(overlay->popup); + } + } else if (overlay->popup) { + if (overlay->obj) { + evas_object_del(overlay->obj); + overlay->obj = NULL; + } + if (overlay->popup) { + e_object_del(E_OBJECT(overlay->popup)); + overlay->popup = NULL; + } + } + + /* move right */ + overlay = &_G.move_overlays[MOVE_RIGHT]; + if ((_G.tinfo->conf->use_rows && l->next) + || (!_G.tinfo->conf->use_rows && ( + stack != TILING_MAX_STACKS - 1 + && ((stack == nb_stacks - 1 && _G.tinfo->stacks[stack]->next) + || (stack != nb_stacks - 1))))) { + if (overlay->popup) { + Evas_Coord ew, eh; + + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_move(_G.move_overlays[MOVE_RIGHT].popup, + extra->expected.x + extra->expected.w - ew/2, + extra->expected.y + extra->expected.h/2 - eh/2); + } else { + Evas_Coord ew, eh; + + overlay->popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!overlay->popup) + return; + + e_popup_layer_set(overlay->popup, TILING_POPUP_LAYER); + overlay->obj = edje_object_add(overlay->popup->evas); + _theme_edje_object_set(overlay->obj, + "modules/tiling/move/right"); + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_edje_bg_object_set(overlay->popup, + overlay->obj); + evas_object_show(overlay->obj); + e_popup_move_resize(overlay->popup, + extra->expected.x + extra->expected.w - ew/2 + - overlay->popup->zone->x, + extra->expected.y + extra->expected.h/2 + - eh/2 + - overlay->popup->zone->y, + ew, + eh); + evas_object_resize(overlay->obj, ew, eh); + + e_popup_show(overlay->popup); + } + } else if (overlay->popup) { + if (overlay->obj) { + evas_object_del(overlay->obj); + overlay->obj = NULL; + } + if (overlay->popup) { + e_object_del(E_OBJECT(overlay->popup)); + overlay->popup = NULL; + } + } + + /* move up */ + overlay = &_G.move_overlays[MOVE_UP]; + if ((!_G.tinfo->conf->use_rows && l->prev) + || (_G.tinfo->conf->use_rows && stack > 0)) { + if (overlay->popup) { + Evas_Coord ew, eh; + + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_move(_G.move_overlays[MOVE_UP].popup, + extra->expected.x + extra->expected.w/2 - ew/2, + extra->expected.y - eh/2); + } else { + Evas_Coord ew, eh; + + overlay->popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!overlay->popup) + return; + + e_popup_layer_set(overlay->popup, TILING_POPUP_LAYER); + overlay->obj = edje_object_add(overlay->popup->evas); + _theme_edje_object_set(overlay->obj, "modules/tiling/move/up"); + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_edje_bg_object_set(overlay->popup, + overlay->obj); + evas_object_show(overlay->obj); + e_popup_move_resize(overlay->popup, + extra->expected.x + extra->expected.w/2 + - ew/2 + - overlay->popup->zone->x, + extra->expected.y - eh/2 + - overlay->popup->zone->y, + ew, + eh); + evas_object_resize(overlay->obj, ew, eh); + + e_popup_show(overlay->popup); + } + } else if (overlay->popup) { + if (overlay->obj) { + evas_object_del(overlay->obj); + overlay->obj = NULL; + } + if (overlay->popup) { + e_object_del(E_OBJECT(overlay->popup)); + overlay->popup = NULL; + } + } + + /* move down */ + overlay = &_G.move_overlays[MOVE_DOWN]; + if ((!_G.tinfo->conf->use_rows && l->next) + || (_G.tinfo->conf->use_rows && ( + stack != TILING_MAX_STACKS - 1 + && ((stack == nb_stacks - 1 && _G.tinfo->stacks[stack]->next) + || (stack != nb_stacks - 1))))) { + if (overlay->popup) { + Evas_Coord ew, eh; + + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_move(_G.move_overlays[MOVE_DOWN].popup, + extra->expected.x + extra->expected.w/2 - ew/2, + extra->expected.y + extra->expected.h - eh/2); + } else { + Evas_Coord ew, eh; + + overlay->popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!overlay->popup) + return; + + e_popup_layer_set(overlay->popup, TILING_POPUP_LAYER); + overlay->obj = edje_object_add(overlay->popup->evas); + _theme_edje_object_set(overlay->obj, + "modules/tiling/move/down"); + edje_object_size_min_calc(overlay->obj, &ew, &eh); + e_popup_edje_bg_object_set(overlay->popup, + overlay->obj); + evas_object_show(overlay->obj); + e_popup_move_resize(overlay->popup, + extra->expected.x + extra->expected.w/2 + - ew/2 + - overlay->popup->zone->x, + extra->expected.y + extra->expected.h - eh/2 + - overlay->popup->zone->y, + ew, + eh); + evas_object_resize(overlay->obj, ew, eh); + + e_popup_show(overlay->popup); + } + } else if (overlay->popup) { + if (overlay->obj) { + evas_object_del(overlay->obj); + overlay->obj = NULL; + } + if (overlay->popup) { + e_object_del(E_OBJECT(overlay->popup)); + overlay->popup = NULL; + } + } +} + +static void +_move_up_cols(void) +{ + E_Border *bd_1 = _G.focused_bd, + *bd_2 = NULL; + Border_Extra *extra_1 = NULL, + *extra_2 = NULL; + Eina_List *l_1 = NULL, + *l_2 = NULL; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack < 0) + return; + + if (_G.tinfo->stacks[stack]->data == _G.focused_bd) + return; + + l_1 = eina_list_data_find_list(_G.tinfo->stacks[stack], bd_1); + if (!l_1 || !l_1->prev) + return; + l_2 = l_1->prev; + bd_2 = l_2->data; + + extra_1 = eina_hash_find(_G.border_extras, &bd_1); + if (!extra_1) { + ERR("No extra for %p", bd_1); + return; + } + extra_2 = eina_hash_find(_G.border_extras, &bd_2); + if (!extra_2) { + ERR("No extra for %p", bd_2); + return; + } + + l_1->data = bd_2; + l_2->data = bd_1; + + extra_1->expected.y = extra_2->expected.y; + extra_2->expected.y += extra_1->expected.h; + + _e_border_move(bd_1, + extra_1->expected.x, + extra_1->expected.y); + _e_border_move(bd_2, + extra_2->expected.x, + extra_2->expected.y); + + _check_moving_anims(bd_1, extra_1, stack); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra_1->expected.x + extra_1->expected.w/2, + extra_1->expected.y + extra_1->expected.h/2); +} + +static void +_move_down_cols(void) +{ + E_Border *bd_1 = _G.focused_bd, + *bd_2 = NULL; + Border_Extra *extra_1 = NULL, + *extra_2 = NULL; + Eina_List *l_1 = NULL, + *l_2 = NULL; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack < 0) + return; + + l_1 = eina_list_data_find_list(_G.tinfo->stacks[stack], bd_1); + if (!l_1 || !l_1->next) + return; + l_2 = l_1->next; + bd_2 = l_2->data; + + extra_1 = eina_hash_find(_G.border_extras, &bd_1); + if (!extra_1) { + ERR("No extra for %p", bd_1); + return; + } + extra_2 = eina_hash_find(_G.border_extras, &bd_2); + if (!extra_2) { + ERR("No extra for %p", bd_2); + return; + } + + l_1->data = bd_2; + l_2->data = bd_1; + + extra_2->expected.y = extra_1->expected.y; + extra_1->expected.y += extra_2->expected.h; + + _e_border_move(bd_1, + extra_1->expected.x, + extra_1->expected.y); + _e_border_move(bd_2, + extra_2->expected.x, + extra_2->expected.y); + + _check_moving_anims(bd_1, extra_1, stack); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra_1->expected.x + extra_1->expected.w/2, + extra_1->expected.y + extra_1->expected.h/2); +} + +static void +_move_left_cols(void) +{ + E_Border *bd = _G.focused_bd; + Border_Extra *extra; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack <= 0) + return; + + + EINA_LIST_REMOVE(_G.tinfo->stacks[stack], bd); + EINA_LIST_APPEND(_G.tinfo->stacks[stack - 1], bd); + + if (!_G.tinfo->stacks[stack]) { + int x, y, w, h; + int width = 0; + int nb_stacks; + + /* Remove stack */ + nb_stacks = get_stack_count(); + + e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); + + for (int i = stack; i < nb_stacks; i++) { + _G.tinfo->stacks[i] = _G.tinfo->stacks[i+1]; + } + _G.tinfo->stacks[nb_stacks] = NULL; + for (int i = 0; i < nb_stacks; i++) { + + width = w / (nb_stacks - i); + + _set_stack_geometry(i, x, width); + + w -= width; + x += width; + } + _reorganize_stack(stack - 1); + } else { + _reorganize_stack(stack); + _reorganize_stack(stack - 1); + } + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + _check_moving_anims(bd, extra, stack - 1); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra->expected.x + extra->expected.w/2, + extra->expected.y + extra->expected.h/2); +} + +static void +_move_right_cols(void) +{ + E_Border *bd = _G.focused_bd; + int stack; + int nb_stacks; + Border_Extra *extra; + + stack = get_stack(bd); + if (stack == TILING_MAX_STACKS - 1) + return; + + nb_stacks = get_stack_count(); + if (stack == nb_stacks - 1 && !_G.tinfo->stacks[stack]->next) + return; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + EINA_LIST_REMOVE(_G.tinfo->stacks[stack], bd); + EINA_LIST_APPEND(_G.tinfo->stacks[stack + 1], bd); + + if (_G.tinfo->stacks[stack] && _G.tinfo->stacks[stack + 1]->next) { + _reorganize_stack(stack); + _reorganize_stack(stack + 1); + _check_moving_anims(bd, extra, stack + 1); + } else + if (_G.tinfo->stacks[stack]) { + /* Add stack */ + int x, y, w, h; + int width = 0; + + _reorganize_stack(stack); + + e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); + + for (int i = 0; i < nb_stacks; i++) { + + width = w / (nb_stacks + 1 - i); + + _set_stack_geometry(i, x, width); + + w -= width; + x += width; + } + + _G.tinfo->pos[nb_stacks] = x; + _G.tinfo->size[nb_stacks] = width; + extra->expected.x = x; + extra->expected.y = y; + extra->expected.w = width; + extra->expected.h = h; + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_VERTICAL); + + if (nb_stacks + 1 > _G.tinfo->conf->nb_stacks) { + _G.tinfo->conf->nb_stacks = nb_stacks + 1; + e_config_save_queue(); + } + _check_moving_anims(bd, extra, stack + 1); + } else { + int x, y, w, h; + int width; + + e_zone_useful_geometry_get(_G.tinfo->desk->zone, &x, &y, &w, &h); + for (int i = stack; i < nb_stacks; i++) { + _G.tinfo->stacks[i] = _G.tinfo->stacks[i + 1]; + } + nb_stacks--; + for (int i = 0; i < nb_stacks; i++) { + width = w / (nb_stacks - i); + + _set_stack_geometry(i, x, width); + + w -= width; + x += width; + } + _G.tinfo->stacks[nb_stacks] = NULL; + _G.tinfo->pos[nb_stacks] = 0; + _G.tinfo->size[nb_stacks] = 0; + _reorganize_stack(stack); + _check_moving_anims(bd, extra, stack); + } + + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra->expected.x + extra->expected.w/2, + extra->expected.y + extra->expected.h/2); +} + +static void +_move_left_rows(void) +{ + E_Border *bd_1 = _G.focused_bd, + *bd_2 = NULL; + Border_Extra *extra_1 = NULL, + *extra_2 = NULL; + Eina_List *l_1 = NULL, + *l_2 = NULL; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack < 0) + return; + + if (_G.tinfo->stacks[stack]->data == _G.focused_bd) + return; + + l_1 = eina_list_data_find_list(_G.tinfo->stacks[stack], bd_1); + if (!l_1 || !l_1->prev) + return; + l_2 = l_1->prev; + bd_2 = l_2->data; + + extra_1 = eina_hash_find(_G.border_extras, &bd_1); + if (!extra_1) { + ERR("No extra for %p", bd_1); + return; + } + extra_2 = eina_hash_find(_G.border_extras, &bd_2); + if (!extra_2) { + ERR("No extra for %p", bd_2); + return; + } + + l_1->data = bd_2; + l_2->data = bd_1; + + extra_1->expected.x = extra_2->expected.x; + extra_2->expected.x += extra_1->expected.w; + + _e_border_move(bd_1, + extra_1->expected.x, + extra_1->expected.y); + _e_border_move(bd_2, + extra_2->expected.x, + extra_2->expected.y); + + _check_moving_anims(bd_1, extra_1, stack); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra_1->expected.x + extra_1->expected.w/2, + extra_1->expected.y + extra_1->expected.h/2); +} + +static void +_move_right_rows(void) +{ + E_Border *bd_1 = _G.focused_bd, + *bd_2 = NULL; + Border_Extra *extra_1 = NULL, + *extra_2 = NULL; + Eina_List *l_1 = NULL, + *l_2 = NULL; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack < 0) + return; + + l_1 = eina_list_data_find_list(_G.tinfo->stacks[stack], bd_1); + if (!l_1 || !l_1->next) + return; + l_2 = l_1->next; + bd_2 = l_2->data; + + extra_1 = eina_hash_find(_G.border_extras, &bd_1); + if (!extra_1) { + ERR("No extra for %p", bd_1); + return; + } + extra_2 = eina_hash_find(_G.border_extras, &bd_2); + if (!extra_2) { + ERR("No extra for %p", bd_2); + return; + } + + l_1->data = bd_2; + l_2->data = bd_1; + + extra_2->expected.x = extra_1->expected.x; + extra_1->expected.x += extra_2->expected.w; + + _e_border_move(bd_1, + extra_1->expected.x, + extra_1->expected.y); + _e_border_move(bd_2, + extra_2->expected.x, + extra_2->expected.y); + + _check_moving_anims(bd_1, extra_1, stack); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra_1->expected.x + extra_1->expected.w/2, + extra_1->expected.y + extra_1->expected.h/2); +} + +static void +_move_up_rows(void) +{ + E_Border *bd = _G.focused_bd; + Border_Extra *extra; + int stack; + + stack = get_stack(_G.focused_bd); + if (stack <= 0) + return; + + + EINA_LIST_REMOVE(_G.tinfo->stacks[stack], bd); + EINA_LIST_APPEND(_G.tinfo->stacks[stack - 1], bd); + + if (!_G.tinfo->stacks[stack]) { + int x, y, w, h; + int nb_stacks; + + /* Remove stack */ + nb_stacks = get_stack_count(); + + e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); + + for (int i = stack; i < nb_stacks; i++) { + _G.tinfo->stacks[i] = _G.tinfo->stacks[i+1]; + } + _G.tinfo->stacks[nb_stacks] = NULL; + for (int i = 0; i < nb_stacks; i++) { + int height = 0; + + height = h / (nb_stacks - i); + + _set_stack_geometry(i, y, height); + + h -= height; + y += height; + } + _reorganize_stack(stack - 1); + } else { + _reorganize_stack(stack); + _reorganize_stack(stack - 1); + } + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + _check_moving_anims(bd, extra, stack - 1); + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra->expected.x + extra->expected.w/2, + extra->expected.y + extra->expected.h/2); +} + +static void +_move_down_rows(void) +{ + E_Border *bd = _G.focused_bd; + int stack; + int nb_stacks; + Border_Extra *extra; + + stack = get_stack(bd); + if (stack == TILING_MAX_STACKS - 1) + return; + + nb_stacks = get_stack_count(); + if (stack == nb_stacks - 1 && !_G.tinfo->stacks[stack]->next) + return; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + EINA_LIST_REMOVE(_G.tinfo->stacks[stack], bd); + EINA_LIST_APPEND(_G.tinfo->stacks[stack + 1], bd); + + if (_G.tinfo->stacks[stack] && _G.tinfo->stacks[stack + 1]->next) { + _reorganize_stack(stack); + _reorganize_stack(stack + 1); + _check_moving_anims(bd, extra, stack + 1); + } else + if (_G.tinfo->stacks[stack]) { + /* Add stack */ + int x, y, w, h; + int height = 0; + + _reorganize_stack(stack); + + e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); + + for (int i = 0; i < nb_stacks; i++) { + + height = h / (nb_stacks + 1 - i); + + _set_stack_geometry(i, y, height); + + h -= height; + y += height; + } + + _G.tinfo->pos[nb_stacks] = y; + _G.tinfo->size[nb_stacks] = height; + extra->expected.x = x; + extra->expected.y = y; + extra->expected.w = w; + extra->expected.h = height; + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_HORIZONTAL); + + if (nb_stacks + 1 > _G.tinfo->conf->nb_stacks) { + _G.tinfo->conf->nb_stacks = nb_stacks + 1; + e_config_save_queue(); + } + _check_moving_anims(bd, extra, stack + 1); + } else { + int x, y, w, h; + + e_zone_useful_geometry_get(_G.tinfo->desk->zone, &x, &y, &w, &h); + for (int i = stack; i < nb_stacks; i++) { + _G.tinfo->stacks[i] = _G.tinfo->stacks[i + 1]; + } + nb_stacks--; + for (int i = 0; i < nb_stacks; i++) { + int height; + + height = h / (nb_stacks - i); + + _set_stack_geometry(i, y, height); + + h -= height; + y += height; + } + _G.tinfo->stacks[nb_stacks] = NULL; + _G.tinfo->pos[nb_stacks] = 0; + _G.tinfo->size[nb_stacks] = 0; + _reorganize_stack(stack); + _check_moving_anims(bd, extra, stack); + } + + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + extra->expected.x + extra->expected.w/2, + extra->expected.y + extra->expected.h/2); +} + +static Eina_Bool +move_key_down(void *data, + int type, + void *event) +{ + Ecore_Event_Key *ev = event; + + if (ev->event_window != _G.action_input_win) + return ECORE_CALLBACK_PASS_ON; + + /* reset timer */ + ecore_timer_delay(_G.action_timer, TILING_OVERLAY_TIMEOUT + - ecore_timer_pending_get(_G.action_timer)); + + if ((strcmp(ev->key, "Up") == 0) + || (strcmp(ev->key, "k") == 0)) + { + if (_G.tinfo->conf->use_rows) + _move_up_rows(); + else + _move_up_cols(); + return ECORE_CALLBACK_PASS_ON; + } else if ((strcmp(ev->key, "Down") == 0) + || (strcmp(ev->key, "j") == 0)) + { + if (_G.tinfo->conf->use_rows) + _move_down_rows(); + else + _move_down_cols(); + return ECORE_CALLBACK_PASS_ON; + } else if ((strcmp(ev->key, "Left") == 0) + || (strcmp(ev->key, "h") == 0)) + { + if (_G.tinfo->conf->use_rows) + _move_left_rows(); + else + _move_left_cols(); + return ECORE_CALLBACK_PASS_ON; + } else if ((strcmp(ev->key, "Right") == 0) + || (strcmp(ev->key, "l") == 0)) + { + if (_G.tinfo->conf->use_rows) + _move_right_rows(); + else + _move_right_cols(); + return ECORE_CALLBACK_PASS_ON; + } + + if (strcmp(ev->key, "Return") == 0) + goto stop; + if (strcmp(ev->key, "Escape") == 0) + goto stop; /* TODO: fallback */ + + return ECORE_CALLBACK_PASS_ON; +stop: + end_special_input(); + return ECORE_CALLBACK_DONE; +} + +static void +_e_mod_action_move_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk; + E_Border *focused_bd; + Ecore_X_Window parent; + + desk = get_current_desk(); + if (!desk) + return; + + focused_bd = e_border_focused_get(); + if (!focused_bd || focused_bd->desk != desk) + return; + + check_tinfo(desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + _G.focused_bd = focused_bd; + + _G.input_mode = INPUT_MODE_MOVING; + + /* Get input */ + parent = focused_bd->zone->container->win; + _G.action_input_win = ecore_x_window_input_new(parent, 0, 0, 1, 1); + if (!_G.action_input_win) { + end_special_input(); + return; + } + + ecore_x_window_show(_G.action_input_win); + if (!e_grabinput_get(_G.action_input_win, 0, _G.action_input_win)) { + end_special_input(); + return; + } + _G.action_timer = ecore_timer_add(TILING_OVERLAY_TIMEOUT, + _timeout_cb, NULL); + + _G.handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + move_key_down, NULL); + _check_moving_anims(focused_bd, NULL, -1); +} + +/* }}} */ +/* Adjust Transitions {{{ */ + +static void +_transition_overlays_free_cb(void *data) +{ + transition_overlay_t *trov = data; + + if (trov->overlay.obj) { + evas_object_del(trov->overlay.obj); + trov->overlay.obj = NULL; + } + if (trov->overlay.popup) { + e_object_del(E_OBJECT(trov->overlay.popup)); + trov->overlay.popup = NULL; + } + if (trov != _G.transition_overlay) { + E_FREE(trov); + } +} + +static void +_transition_move_cols(tiling_move_t direction) +{ + int delta = TILING_RESIZE_STEP; + int stack; + E_Popup *popup = NULL; + + if (!_G.transition_overlay) + return; + + stack = _G.transition_overlay->stack; + + if (_G.transition_overlay->bd) { + Eina_List *l = NULL; + E_Border *bd = _G.transition_overlay->bd, + *nextbd = NULL; + Border_Extra *extra = NULL, + *nextextra = NULL; + int min_height = 0; + + l = eina_list_data_find_list(_G.tinfo->stacks[stack], bd); + if (!l) { + ERR("unable to bd %p in stack %d", bd, stack); + return; + } + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + nextbd = l->next->data; + nextextra = eina_hash_find(_G.border_extras, &nextbd); + if (!nextextra) { + ERR("No extra for %p", nextbd); + return; + } + + if (direction == MOVE_UP) { + delta *= -1; + } + + nextbd = l->next->data; + min_height = MAX(nextbd->client.icccm.base_h, 1); + + if (nextextra->expected.h - delta < min_height) + delta = nextextra->expected.h - min_height; + + nextextra->expected.y += delta; + nextextra->expected.h -= delta; + _e_border_move_resize(nextbd, + nextextra->expected.x, + nextextra->expected.y, + nextextra->expected.w, + nextextra->expected.h); + + extra->expected.h += delta; + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + + popup = _G.transition_overlay->overlay.popup; + e_popup_move(popup, popup->x, popup->y + delta); + } else { + + if (stack == TILING_MAX_STACKS || !_G.tinfo->stacks[stack + 1]) { + return; + } + if (direction == MOVE_LEFT) { + delta *= -1; + } + + if (delta + 1 > _G.tinfo->size[stack + 1]) + delta = _G.tinfo->size[stack + 1] - 1; + + _move_resize_stack(stack, 0, delta); + _move_resize_stack(stack+1, delta, -delta); + + popup = _G.transition_overlay->overlay.popup; + e_popup_move(popup, popup->x + delta, popup->y); + } +} + +static void +_transition_move_rows(tiling_move_t direction) +{ + int delta = TILING_RESIZE_STEP; + int stack; + E_Popup *popup = NULL; + + if (!_G.transition_overlay) + return; + + stack = _G.transition_overlay->stack; + + if (_G.transition_overlay->bd) { + Eina_List *l = NULL; + E_Border *bd = _G.transition_overlay->bd, + *nextbd = NULL; + Border_Extra *extra = NULL, + *nextextra = NULL; + int min_width = 0; + + l = eina_list_data_find_list(_G.tinfo->stacks[stack], bd); + if (!l) { + ERR("unable to bd %p in stack %d", bd, stack); + return; + } + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + nextbd = l->next->data; + nextextra = eina_hash_find(_G.border_extras, &nextbd); + if (!nextextra) { + ERR("No extra for %p", nextbd); + return; + } + + if (direction == MOVE_LEFT) { + delta *= -1; + } + + nextbd = l->next->data; + min_width = MAX(nextbd->client.icccm.base_w, 1); + + if (nextextra->expected.w - delta < min_width) + delta = nextextra->expected.w - min_width; + + nextextra->expected.x += delta; + nextextra->expected.w -= delta; + _e_border_move_resize(nextbd, + nextextra->expected.x, + nextextra->expected.y, + nextextra->expected.w, + nextextra->expected.h); + + extra->expected.w += delta; + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + + popup = _G.transition_overlay->overlay.popup; + e_popup_move(popup, popup->x + delta, popup->y); + } else { + + if (stack == TILING_MAX_STACKS || !_G.tinfo->stacks[stack + 1]) { + return; + } + if (direction == MOVE_UP) { + delta *= -1; + } + + if (delta + 1 > _G.tinfo->size[stack + 1]) + delta = _G.tinfo->size[stack + 1] - 1; + + _move_resize_stack(stack, 0, delta); + _move_resize_stack(stack+1, delta, -delta); + + popup = _G.transition_overlay->overlay.popup; + e_popup_move(popup, popup->x, popup->y + delta); + } +} + +static Eina_Bool +_transition_overlay_key_down(void *data, + int type, + void *event) +{ + Ecore_Event_Key *ev = event; + + if (ev->event_window != _G.action_input_win) + return ECORE_CALLBACK_PASS_ON; + + if (strcmp(ev->key, "Return") == 0) + goto stop; + if (strcmp(ev->key, "Escape") == 0) + goto stop; + + /* reset timer */ + ecore_timer_delay(_G.action_timer, TILING_OVERLAY_TIMEOUT + - ecore_timer_pending_get(_G.action_timer)); + + if (_G.transition_overlay) { + DBG("ev->key='%s'; %p %d", ev->key, + _G.transition_overlay->bd, _G.tinfo->conf->use_rows); + if ((strcmp(ev->key, "Up") == 0) + || (strcmp(ev->key, "k") == 0)) + { + if (_G.transition_overlay->bd && !_G.tinfo->conf->use_rows) { + _transition_move_cols(MOVE_UP); + return ECORE_CALLBACK_PASS_ON; + } else + if (!_G.transition_overlay->bd && _G.tinfo->conf->use_rows) { + _transition_move_rows(MOVE_UP); + return ECORE_CALLBACK_PASS_ON; + } + } else + if ((strcmp(ev->key, "Down") == 0) + || (strcmp(ev->key, "j") == 0)) + { + if (_G.transition_overlay->bd && !_G.tinfo->conf->use_rows) { + _transition_move_cols(MOVE_DOWN); + return ECORE_CALLBACK_PASS_ON; + } else + if (!_G.transition_overlay->bd && _G.tinfo->conf->use_rows) { + _transition_move_rows(MOVE_DOWN); + return ECORE_CALLBACK_PASS_ON; + } + } else + if ((strcmp(ev->key, "Left") == 0) + || (strcmp(ev->key, "h") == 0)) + { + if (!_G.transition_overlay->bd && !_G.tinfo->conf->use_rows) { + _transition_move_cols(MOVE_LEFT); + return ECORE_CALLBACK_PASS_ON; + } else + if (_G.transition_overlay->bd && _G.tinfo->conf->use_rows) { + _transition_move_rows(MOVE_LEFT); + return ECORE_CALLBACK_PASS_ON; + } + } else + if ((strcmp(ev->key, "Right") == 0) + || (strcmp(ev->key, "l") == 0)) + { + if (!_G.transition_overlay->bd && !_G.tinfo->conf->use_rows) { + _transition_move_cols(MOVE_RIGHT); + return ECORE_CALLBACK_PASS_ON; + } else + if (_G.transition_overlay->bd && _G.tinfo->conf->use_rows) { + _transition_move_rows(MOVE_RIGHT); + return ECORE_CALLBACK_PASS_ON; + } + } + + return ECORE_CALLBACK_RENEW; + } else { + if (strcmp(ev->key, "Backspace") == 0) { + char *key = _G.keys; + + while (*key) + key++; + *key = '\0'; + return ECORE_CALLBACK_RENEW; + } + if (ev->key[0] && !ev->key[1] && strchr(tiling_g.config->keyhints, + ev->key[1])) + { + transition_overlay_t *trov = NULL; + E_Border *bd = NULL; + Border_Extra *extra = NULL; + Evas_Coord ew, eh; + char *key = _G.keys; + + while (*key) + key++; + *key++ = ev->key[0]; + *key = '\0'; + + trov = eina_hash_find(_G.overlays, _G.keys); + if (!trov) { + return ECORE_CALLBACK_RENEW; + } + bd = trov->bd; + + _G.transition_overlay = trov; + eina_hash_free(_G.overlays); + _G.overlays = NULL; + + if (bd) { + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + goto stop; + } + } + if (!trov->overlay.popup) { + trov->overlay.popup = e_popup_new(_G.tinfo->desk->zone, + 0, 0, 1, 1); + e_popup_layer_set(trov->overlay.popup, TILING_POPUP_LAYER); + } + if (!trov->overlay.obj) { + trov->overlay.obj = + edje_object_add(trov->overlay.popup->evas); + } + if ((bd && !_G.tinfo->conf->use_rows) + || (!bd && _G.tinfo->conf->use_rows)) { + _theme_edje_object_set(trov->overlay.obj, + "modules/tiling/transition/horizontal"); + } else { + _theme_edje_object_set(trov->overlay.obj, + "modules/tiling/transition/vertical"); + } + + edje_object_size_min_calc(trov->overlay.obj, &ew, &eh); + e_popup_edje_bg_object_set(trov->overlay.popup, + trov->overlay.obj); + evas_object_show(trov->overlay.obj); + if (bd) { + if (_G.tinfo->conf->use_rows) { + e_popup_move_resize(trov->overlay.popup, + (extra->expected.x - trov->overlay.popup->zone->x + + extra->expected.w - (ew / 2)), + (extra->expected.y - trov->overlay.popup->zone->y + + ((extra->expected.h - eh) / 2)), + ew, eh); + } else { + e_popup_move_resize(trov->overlay.popup, + (extra->expected.x - trov->overlay.popup->zone->x + + ((extra->expected.w - ew) / 2)), + (extra->expected.y - trov->overlay.popup->zone->y + + extra->expected.h - (eh / 2)), + ew, eh); + } + } else { + if (_G.tinfo->conf->use_rows) { + e_popup_move_resize(trov->overlay.popup, + (trov->overlay.popup->zone->w/2 - ew/2), + (_G.tinfo->pos[trov->stack] + + _G.tinfo->size[trov->stack] + - trov->overlay.popup->zone->y - eh/2), + ew, eh); + } else { + e_popup_move_resize(trov->overlay.popup, + (_G.tinfo->pos[trov->stack] + + _G.tinfo->size[trov->stack] + - trov->overlay.popup->zone->x - ew/2), + (trov->overlay.popup->zone->h/2 - eh/2), + ew, eh); + } + } + evas_object_resize(trov->overlay.obj, ew, eh); + e_popup_show(trov->overlay.popup); + + return ECORE_CALLBACK_RENEW; + } + } + +stop: + end_special_input(); + return ECORE_CALLBACK_DONE; +} + +static void +_do_transition_overlay(void) +{ + int nb_transitions; + Ecore_X_Window parent; + int hints_len; + int key_len; + int n = 0; + int nmax; + + end_special_input(); + + nb_transitions = get_transition_count(); + if (nb_transitions < 1) { + return; + } + + _G.input_mode = INPUT_MODE_TRANSITION; + + _G.overlays = eina_hash_string_small_new(_transition_overlays_free_cb); + hints_len = strlen(tiling_g.config->keyhints); + key_len = 1; + nmax = hints_len; + if (hints_len < nb_transitions) { + key_len = 2; + nmax *= hints_len; + if (hints_len * hints_len < nb_transitions) { + key_len = 3; + nmax *= hints_len; + } + } + + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + Eina_List *l; + E_Border *bd; + + if (!_G.tinfo->stacks[i]) + break; + EINA_LIST_FOREACH(_G.tinfo->stacks[i], l, bd) { + if (l->next && n < nmax) { + Border_Extra *extra; + Evas_Coord ew, eh; + transition_overlay_t *trov; + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + continue; + } + + trov = E_NEW(transition_overlay_t, 1); + + trov->overlay.popup = e_popup_new(bd->zone, 0, 0, 1, 1); + if (!trov->overlay.popup) + continue; + + e_popup_layer_set(trov->overlay.popup, TILING_POPUP_LAYER); + trov->overlay.obj = edje_object_add(trov->overlay.popup->evas); + e_theme_edje_object_set(trov->overlay.obj, + "base/theme/borders", + "e/widgets/border/default/resize"); + + switch (key_len) { + case 1: + trov->key[0] = tiling_g.config->keyhints[n]; + trov->key[1] = '\0'; + break; + case 2: + trov->key[0] = tiling_g.config->keyhints[n / hints_len]; + trov->key[1] = tiling_g.config->keyhints[n % hints_len]; + trov->key[2] = '\0'; + break; + case 3: + trov->key[0] = tiling_g.config->keyhints[n / hints_len / hints_len]; + trov->key[0] = tiling_g.config->keyhints[n / hints_len]; + trov->key[1] = tiling_g.config->keyhints[n % hints_len]; + trov->key[2] = '\0'; + break; + } + n++; + trov->stack = i; + trov->bd = bd; + + eina_hash_add(_G.overlays, trov->key, trov); + edje_object_part_text_set(trov->overlay.obj, + "e.text.label", + trov->key); + edje_object_size_min_calc(trov->overlay.obj, &ew, &eh); + evas_object_move(trov->overlay.obj, 0, 0); + evas_object_resize(trov->overlay.obj, ew, eh); + evas_object_show(trov->overlay.obj); + e_popup_edje_bg_object_set(trov->overlay.popup, + trov->overlay.obj); + + evas_object_show(trov->overlay.obj); + e_popup_show(trov->overlay.popup); + + if (_G.tinfo->conf->use_rows) { + e_popup_move_resize(trov->overlay.popup, + (extra->expected.x - trov->overlay.popup->zone->x + + extra->expected.w - (ew / 2)), + (extra->expected.y - trov->overlay.popup->zone->y + + ((extra->expected.h - eh) / 2)), + ew, eh); + } else { + e_popup_move_resize(trov->overlay.popup, + (extra->expected.x - trov->overlay.popup->zone->x + + ((extra->expected.w - ew) / 2)), + (extra->expected.y - trov->overlay.popup->zone->y + + extra->expected.h - (eh / 2)), + ew, eh); + } + + e_popup_show(trov->overlay.popup); + } + } + if (i != TILING_MAX_STACKS && _G.tinfo->stacks[i+1] && n < nmax) { + Evas_Coord ew, eh; + transition_overlay_t *trov; + + trov = E_NEW(transition_overlay_t, 1); + + trov->overlay.popup = e_popup_new(_G.tinfo->desk->zone, + 0, 0, 1, 1); + if (!trov->overlay.popup) + continue; + + e_popup_layer_set(trov->overlay.popup, TILING_POPUP_LAYER); + trov->overlay.obj = edje_object_add(trov->overlay.popup->evas); + e_theme_edje_object_set(trov->overlay.obj, + "base/theme/borders", + "e/widgets/border/default/resize"); + + switch (key_len) { + case 1: + trov->key[0] = tiling_g.config->keyhints[n]; + trov->key[1] = '\0'; + break; + case 2: + trov->key[0] = tiling_g.config->keyhints[n / hints_len]; + trov->key[1] = tiling_g.config->keyhints[n % hints_len]; + trov->key[2] = '\0'; + break; + case 3: + trov->key[0] = tiling_g.config->keyhints[n / hints_len / hints_len]; + trov->key[0] = tiling_g.config->keyhints[n / hints_len]; + trov->key[1] = tiling_g.config->keyhints[n % hints_len]; + trov->key[2] = '\0'; + break; + } + n++; + trov->stack = i; + trov->bd = NULL; + + eina_hash_add(_G.overlays, trov->key, trov); + edje_object_part_text_set(trov->overlay.obj, + "e.text.label", + trov->key); + edje_object_size_min_calc(trov->overlay.obj, &ew, &eh); + evas_object_move(trov->overlay.obj, 0, 0); + evas_object_resize(trov->overlay.obj, ew, eh); + evas_object_show(trov->overlay.obj); + e_popup_edje_bg_object_set(trov->overlay.popup, + trov->overlay.obj); + + evas_object_show(trov->overlay.obj); + e_popup_show(trov->overlay.popup); + + if (_G.tinfo->conf->use_rows) { + e_popup_move_resize(trov->overlay.popup, + (trov->overlay.popup->zone->w/2 - ew/2), + (_G.tinfo->pos[trov->stack] + + _G.tinfo->size[trov->stack] + - trov->overlay.popup->zone->y - eh/2), + ew, eh); + } else { + e_popup_move_resize(trov->overlay.popup, + (_G.tinfo->pos[trov->stack] + + _G.tinfo->size[trov->stack] + - trov->overlay.popup->zone->x - ew/2), + (trov->overlay.popup->zone->h/2 - eh/2), + ew, eh); + } + + e_popup_show(trov->overlay.popup); + } + } + + /* Get input */ + parent = _G.tinfo->desk->zone->container->win; + _G.action_input_win = ecore_x_window_input_new(parent, 0, 0, 1, 1); + if (!_G.action_input_win) { + end_special_input(); + return; + } + + ecore_x_window_show(_G.action_input_win); + if (!e_grabinput_get(_G.action_input_win, 0, _G.action_input_win)) { + end_special_input(); + return; + } + _G.action_timer = ecore_timer_add(TILING_OVERLAY_TIMEOUT, + _timeout_cb, NULL); + + _G.keys[0] = '\0'; + _G.handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + _transition_overlay_key_down, + NULL); +} + +static void +_e_mod_action_adjust_transitions(E_Object *obj, + const char *params) +{ + E_Desk *desk; + + desk = get_current_desk(); + if (!desk) + return; + + check_tinfo(desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + _do_transition_overlay(); +} + +/* }}} */ +/* Go {{{ */ + +static Eina_Bool +_warp_timer(void *_) +{ + if (_G.warp_timer) { + double spd = TILING_WRAP_SPEED; + + _G.old_warp_x = _G.warp_x; + _G.old_warp_y = _G.warp_y; + _G.warp_x = (_G.warp_x * (1.0 - spd)) + (_G.warp_to_x * spd); + _G.warp_y = (_G.warp_y * (1.0 - spd)) + (_G.warp_to_y * spd); + + ecore_x_pointer_warp(_G.tinfo->desk->zone->container->win, + _G.warp_x, _G.warp_y); + + if (abs(_G.warp_x - _G.old_warp_x) <= 1 + && abs(_G.warp_y - _G.old_warp_y) <= 1) { + _G.warp_timer = NULL; + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_RENEW; + } + _G.warp_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_action_go(E_Border *_, + Border_Extra *extra_2) +{ + E_Border *bd = extra_2->border; + + _G.warp_to_x = bd->x + (bd->w / 2); + _G.warp_to_y = bd->y + (bd->h / 2); + ecore_x_pointer_xy_get(_G.tinfo->desk->zone->container->win, + &_G.warp_x, &_G.warp_y); + e_border_focus_latest_set(bd); + _G.warp_timer = ecore_timer_add(0.01, _warp_timer, NULL); +} + +static void +_e_mod_action_go_cb(E_Object *obj, + const char *params) +{ + E_Desk *desk; + + desk = get_current_desk(); + if (!desk) + return; + + check_tinfo(desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + _do_overlay(NULL, _action_go, INPUT_MODE_GOING); +} + +/* }}} */ +/* Hooks {{{*/ + +static void +_pre_border_assign_hook(void *data, + E_Border *bd) +{ + if (tiling_g.config->show_titles) + return; + + if (!bd) { + return; + } + + check_tinfo(bd->desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + if (is_floating_window(bd)) { + return; + } + + if (!is_tilable(bd)) { + return; + } + + if (bd->fullscreen) { + return; + } + + if ((bd->bordername && strcmp(bd->bordername, "pixel")) + || !bd->bordername) + { + change_window_border(bd, "pixel"); + } +} + +static void _move_or_resize(E_Border *bd) +{ + Border_Extra *extra; + int stack = -1; + + if (!bd) { + return; + } + + check_tinfo(bd->desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return; + } + + stack = get_stack(bd); + if (stack < 0) { + return; + } + + DBG("Resize: %p / '%s' / '%s', (%d,%d), changes(size=%d, position=%d, border=%d)" + " g:%dx%d+%d+%d bdname:'%s' (stack:%d%c) maximized:%s fs:%s", + bd, bd->client.icccm.title, bd->client.netwm.name, + bd->desk->x, bd->desk->y, + bd->changes.size, bd->changes.pos, bd->changes.border, + bd->w, bd->h, bd->x, bd->y, bd->bordername, + stack, _G.tinfo->conf->use_rows? 'r':'c', + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_NONE ? "NONE" : + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL ? "VERTICAL" : + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL ? "HORIZONTAL" : + "BOTH", bd->fullscreen? "true": "false"); + + extra = eina_hash_find(_G.border_extras, &bd); + if (!extra) { + ERR("No extra for %p", bd); + return; + } + + DBG("expected: %dx%d+%d+%d", + extra->expected.w, + extra->expected.h, + extra->expected.x, + extra->expected.y); + DBG("delta:%dx%d,%d,%d. step:%dx%d. base:%dx%d", + bd->w - extra->expected.w, bd->h - extra->expected.h, + bd->x - extra->expected.x, bd->y - extra->expected.y, + bd->client.icccm.step_w, bd->client.icccm.step_h, + bd->client.icccm.base_w, bd->client.icccm.base_h); + + if (stack == 0 && !_G.tinfo->stacks[1] && !_G.tinfo->stacks[0]->next) { + if (bd->maximized) { + extra->expected.x = bd->x; + extra->expected.y = bd->y; + extra->expected.w = bd->w; + extra->expected.h = bd->h; + } else { + /* TODO: what if a window doesn't want to be maximized? */ + _e_border_unmaximize(bd, E_MAXIMIZE_BOTH); + _e_border_maximize(bd, E_MAXIMIZE_EXPAND | E_MAXIMIZE_BOTH); + } + } + if (bd->x == extra->expected.x && bd->y == extra->expected.y + && bd->w == extra->expected.w && bd->h == extra->expected.h) + { + return; + } + if (bd->maximized) { + bool changed = false; + + if (_G.tinfo->conf->use_rows) { + if (stack > 0 && bd->maximized & E_MAXIMIZE_VERTICAL) { + _e_border_unmaximize(bd, E_MAXIMIZE_VERTICAL); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + changed = true; + } + if (bd->maximized & E_MAXIMIZE_HORIZONTAL + && eina_list_count(_G.tinfo->stacks[stack]) > 1) { + _e_border_unmaximize(bd, E_MAXIMIZE_HORIZONTAL); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + changed = true; + } + } else { + if (stack > 0 && bd->maximized & E_MAXIMIZE_HORIZONTAL) { + _e_border_unmaximize(bd, E_MAXIMIZE_HORIZONTAL); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + changed = true; + } + if (bd->maximized & E_MAXIMIZE_VERTICAL + && eina_list_count(_G.tinfo->stacks[stack]) > 1) { + _e_border_unmaximize(bd, E_MAXIMIZE_VERTICAL); + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + changed = true; + } + } + if (changed) + return; + } + + if ((bd->changes.border && bd->changes.size) + || bd->x <= 0 || bd->y <= 0) { + _e_border_move_resize(bd, + extra->expected.x, + extra->expected.y, + extra->expected.w, + extra->expected.h); + return; + } + + if (abs(extra->expected.w - bd->w) >= bd->client.icccm.step_w) { + if (_G.tinfo->conf->use_rows) + _move_resize_border_in_stack(bd, extra, stack, TILING_RESIZE); + else + _move_resize_border_stack(bd, extra, stack, TILING_RESIZE); + } + if (abs(extra->expected.h - bd->h) >= bd->client.icccm.step_h) { + if (_G.tinfo->conf->use_rows) + _move_resize_border_stack(bd, extra, stack, TILING_RESIZE); + else + _move_resize_border_in_stack(bd, extra, stack, TILING_RESIZE); + } + if (extra->expected.x != bd->x) { + if (_G.tinfo->conf->use_rows) + _move_resize_border_in_stack(bd, extra, stack, TILING_MOVE); + else + _move_resize_border_stack(bd, extra, stack, TILING_MOVE); + } + if (extra->expected.y != bd->y) { + if (_G.tinfo->conf->use_rows) + _move_resize_border_stack(bd, extra, stack, TILING_MOVE); + else + _move_resize_border_in_stack(bd, extra, stack, TILING_MOVE); + } + + if (_G.input_mode == INPUT_MODE_MOVING + && bd == _G.focused_bd) { + _check_moving_anims(bd, extra, stack); + } +} + +static Eina_Bool +_resize_hook(void *data, int type, E_Event_Border_Resize *event) +{ + E_Border *bd = event->border; + + _move_or_resize(bd); + + return true; +} + +static Eina_Bool +_move_hook(void *data, int type, E_Event_Border_Move*event) +{ + E_Border *bd = event->border; + + _move_or_resize(bd); + + return true; +} + +static Eina_Bool +_add_hook(void *data, int type, E_Event_Border_Add *event) +{ + E_Border *bd = event->border; + int stack = -1; + + if (_G.input_mode != INPUT_MODE_NONE + && _G.input_mode != INPUT_MODE_MOVING + && _G.input_mode != INPUT_MODE_TRANSITION) + { + end_special_input(); + } + + check_tinfo(bd->desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return true; + } + + if (!is_tilable(bd)) { + return true; + } + + stack = get_stack(bd); + if (stack >= 0) { + return true; + } + + DBG("Add: %p / '%s' / '%s', (%d,%d), changes(size=%d, position=%d, border=%d)" + " g:%dx%d+%d+%d bdname:'%s' (stack:%d%c) maximized:%s fs:%s", + bd, bd->client.icccm.title, bd->client.netwm.name, + bd->desk->x, bd->desk->y, + bd->changes.size, bd->changes.pos, bd->changes.border, + bd->w, bd->h, bd->x, bd->y, bd->bordername, + stack, _G.tinfo->conf->use_rows? 'r':'c', + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_NONE ? "NONE" : + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL ? "VERTICAL" : + (bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL ? "HORIZONTAL" : + "BOTH", bd->fullscreen? "true": "false"); + + _add_border(bd); + + return true; +} + +static Eina_Bool +_remove_hook(void *data, int type, E_Event_Border_Remove *event) +{ + E_Border *bd = event->border; + + end_special_input(); + + if (_G.currently_switching_desktop) + return EINA_TRUE; + + check_tinfo(bd->desk); + if (!_G.tinfo->conf) + return EINA_TRUE; + + if (EINA_LIST_IS_IN(_G.tinfo->floating_windows, bd)) { + EINA_LIST_REMOVE(_G.tinfo->floating_windows, bd); + return EINA_TRUE; + } + + _remove_border(bd); + + return EINA_TRUE; +} + +static bool +_iconify_hook(void *_, int type, E_Event_Border_Iconify *event) +{ + E_Border *bd = event->border; + + end_special_input(); + + check_tinfo(bd->desk); + if (!_G.tinfo->conf) + return true; + + if (EINA_LIST_IS_IN(_G.tinfo->floating_windows, bd)) { + return true; + } + + _remove_border(bd); + + return true; +} + +static bool +_uniconify_hook(void *_, int type, E_Event_Border_Uniconify *event) +{ + E_Border *bd = event->border; + int stack = -1; + + if (_G.input_mode != INPUT_MODE_NONE + && _G.input_mode != INPUT_MODE_MOVING + && _G.input_mode != INPUT_MODE_TRANSITION) + { + end_special_input(); + } + + check_tinfo(bd->desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + return true; + } + + if (!is_tilable(bd)) { + return true; + } + + stack = get_stack(bd); + if (stack >= 0) { + return true; + } + _add_border(bd); + + return true; +} + +static Eina_Bool +_stick_hook(void *data, int type, void *event) +{ + DBG("TODO"); + return true; +} + +static Eina_Bool +_unstick_hook(void *data, int type, void *event) +{ + DBG("TODO"); + return true; +} + +static Eina_Bool +_desk_show_hook(void *data, int type, void *event) +{ + _G.currently_switching_desktop = 0; + + end_special_input(); + + return EINA_TRUE; +} + +static Eina_Bool +_desk_before_show_hook(void *data, int type, void *event) +{ + end_special_input(); + + _G.currently_switching_desktop = 1; + + return EINA_TRUE; +} + +static bool +_desk_set_hook(void *data, int type, E_Event_Border_Desk_Set *ev) +{ + DBG("%p: from (%d,%d) to (%d,%d)", ev->border, + ev->desk->x, ev->desk->y, + ev->border->desk->x, ev->border->desk->y); + + end_special_input(); + + check_tinfo(ev->desk); + if (!_G.tinfo->conf) { + return true; + } + + if (get_stack(ev->border) >= 0) { + _remove_border(ev->border); + _restore_border(ev->border); + } + + check_tinfo(ev->border->desk); + if (!_G.tinfo->conf) { + return true; + } + + if (get_stack(ev->border) < 0) + _add_border(ev->border); + + return true; +} + +static bool +_container_resize_hook(void *_, int type, E_Event_Container_Resize *ev) +{ + Eina_List *l; + E_Zone *zone; + + EINA_LIST_FOREACH(ev->container->zones, l, zone) { + for (int x = 0; x < zone->desk_x_count; x++) + { + for (int y = 0; y < zone->desk_y_count; y++) { + E_Desk *desk = zone->desks[x + (y * zone->desk_x_count)]; + Eina_List *wins = NULL; + E_Border *bd; + + check_tinfo(desk); + if (!_G.tinfo->conf || !_G.tinfo->conf->nb_stacks) { + continue; + } + + for (int i = 0; i < TILING_MAX_STACKS; i++) { + EINA_LIST_FREE(_G.tinfo->stacks[i], bd) { + EINA_LIST_APPEND(wins, bd); + _restore_border(bd); + } + _G.tinfo->stacks[i] = NULL; + _G.tinfo->pos[i] = 0; + _G.tinfo->size[i] = 0; + } + + EINA_LIST_FREE(wins, bd) { + _add_border(bd); + } + } + } + } + + return true; +} + +/* }}} */ +/* Module setup {{{*/ + +static void +_clear_info_hash(void *data) +{ + Tiling_Info *ti = data; + + eina_list_free(ti->floating_windows); + for (int i = 0; i < TILING_MAX_STACKS; i++) { + eina_list_free(ti->stacks[i]); + ti->stacks[i] = NULL; + } + E_FREE(ti); +} + +static void +_clear_border_extras(void *data) +{ + Border_Extra *extra = data; + + eina_stringshare_del(extra->orig.bordername); + + E_FREE(extra); +} + +EAPI E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Tiling" +}; + +EAPI void * +e_modapi_init(E_Module *m) +{ + char buf[PATH_MAX]; + E_Desk *desk; + + tiling_g.module = m; + + if (tiling_g.log_domain < 0) { + tiling_g.log_domain = eina_log_domain_register("tiling", NULL); + if (tiling_g.log_domain < 0) { + EINA_LOG_CRIT("could not register log domain 'tiling'"); + } + } + + _G.info_hash = eina_hash_pointer_new(_clear_info_hash); + _G.border_extras = eina_hash_pointer_new(_clear_border_extras); + + _G.pre_border_assign_hook = e_border_hook_add( + E_BORDER_HOOK_EVAL_PRE_BORDER_ASSIGN, + (void (*)(void*,void*))_pre_border_assign_hook, NULL); + +#define HANDLER(_h, _e, _f) \ + _h = ecore_event_handler_add(E_EVENT_##_e, \ + (Ecore_Event_Handler_Cb) _f, \ + NULL); + + HANDLER(_G.handler_border_resize, BORDER_RESIZE, _resize_hook); + HANDLER(_G.handler_border_move, BORDER_MOVE, _move_hook); + HANDLER(_G.handler_border_add, BORDER_ADD, _add_hook); + HANDLER(_G.handler_border_remove, BORDER_REMOVE, _remove_hook); + + HANDLER(_G.handler_border_iconify, BORDER_ICONIFY, _iconify_hook); + HANDLER(_G.handler_border_uniconify, BORDER_UNICONIFY, _uniconify_hook); + HANDLER(_G.handler_border_stick, BORDER_STICK, _stick_hook); + HANDLER(_G.handler_border_unstick, BORDER_UNSTICK, _unstick_hook); + + HANDLER(_G.handler_desk_show, DESK_SHOW, _desk_show_hook); + HANDLER(_G.handler_desk_before_show, DESK_BEFORE_SHOW, _desk_before_show_hook); + HANDLER(_G.handler_desk_set, BORDER_DESK_SET, _desk_set_hook); + HANDLER(_G.handler_container_resize, CONTAINER_RESIZE, _container_resize_hook); +#undef HANDLER + +#define ACTION_ADD(_act, _cb, _title, _value) \ + { \ + E_Action *_action = _act; \ + const char *_name = _value; \ + if ((_action = e_action_add(_name))) { \ + _action->func.go = _cb; \ + e_action_predef_name_set(_("Tiling"), _(_title), _name, \ + NULL, NULL, 0); \ + } \ + } + + /* Module's actions */ + ACTION_ADD(_G.act_togglefloat, _e_mod_action_toggle_floating_cb, + "Toggle floating", "toggle_floating"); + ACTION_ADD(_G.act_addstack, _e_mod_action_add_stack_cb, + "Add a stack", "add_stack"); + ACTION_ADD(_G.act_removestack, _e_mod_action_remove_stack_cb, + "Remove a stack", "remove_stack"); + ACTION_ADD(_G.act_tg_stack, _e_mod_action_tg_stack_cb, + "Toggle between rows and columns", "tg_cols_rows"); + ACTION_ADD(_G.act_swap, _e_mod_action_swap_cb, + "Swap a window with an other", "swap"); + ACTION_ADD(_G.act_move, _e_mod_action_move_cb, + "Move window", "move"); + ACTION_ADD(_G.act_adjusttransitions, _e_mod_action_adjust_transitions, + "Adjust transitions", "adjust_transitions"); + ACTION_ADD(_G.act_go, _e_mod_action_go_cb, + "Focus a particular window", "go"); +#undef ACTION_ADD + + /* Configuration entries */ + snprintf(_G.edj_path, sizeof(_G.edj_path),"%s/e-module-tiling.edj", + e_module_dir_get(m)); + e_configure_registry_category_add("windows", 50, _("Windows"), NULL, + "preferences-system-windows"); + e_configure_registry_item_add("windows/tiling", 150, _("Tiling"), + NULL, _G.edj_path, + e_int_config_tiling_module); + + /* Configuration itself */ + _G.config_edd = E_CONFIG_DD_NEW("Tiling_Config", Config); + _G.vdesk_edd = E_CONFIG_DD_NEW("Tiling_Config_VDesk", + struct _Config_vdesk); + E_CONFIG_VAL(_G.config_edd, Config, tile_dialogs, INT); + E_CONFIG_VAL(_G.config_edd, Config, show_titles, INT); + E_CONFIG_VAL(_G.config_edd, Config, keyhints, STR); + + E_CONFIG_LIST(_G.config_edd, Config, vdesks, _G.vdesk_edd); + E_CONFIG_VAL(_G.vdesk_edd, struct _Config_vdesk, x, INT); + E_CONFIG_VAL(_G.vdesk_edd, struct _Config_vdesk, y, INT); + E_CONFIG_VAL(_G.vdesk_edd, struct _Config_vdesk, zone_num, INT); + E_CONFIG_VAL(_G.vdesk_edd, struct _Config_vdesk, nb_stacks, INT); + E_CONFIG_VAL(_G.vdesk_edd, struct _Config_vdesk, use_rows, INT); + + tiling_g.config = e_config_domain_load("module.tiling", _G.config_edd); + if (!tiling_g.config) { + tiling_g.config = E_NEW(Config, 1); + tiling_g.config->tile_dialogs = 1; + tiling_g.config->show_titles = 1; + } + if (!tiling_g.config->keyhints) + tiling_g.config->keyhints = strdup(tiling_g.default_keyhints); + else + tiling_g.config->keyhints = strdup(tiling_g.config->keyhints); + + E_CONFIG_LIMIT(tiling_g.config->tile_dialogs, 0, 1); + E_CONFIG_LIMIT(tiling_g.config->show_titles, 0, 1); + + for (Eina_List *l = tiling_g.config->vdesks; l; l = l->next) { + struct _Config_vdesk *vd; + + vd = l->data; + + E_CONFIG_LIMIT(vd->nb_stacks, 0, TILING_MAX_STACKS); + E_CONFIG_LIMIT(vd->use_rows, 0, 1); + } + + desk = get_current_desk(); + _G.tinfo = _initialize_tinfo(desk); + + _G.input_mode = INPUT_MODE_NONE; + _G.currently_switching_desktop = 0; + _G.action_cb = NULL; + + return m; +} + +EAPI int +e_modapi_shutdown(E_Module *m) +{ + + if (tiling_g.log_domain >= 0) { + eina_log_domain_unregister(tiling_g.log_domain); + tiling_g.log_domain = -1; + } + + if (_G.pre_border_assign_hook) { + e_border_hook_del(_G.pre_border_assign_hook); + _G.pre_border_assign_hook = NULL; + } + +#define FREE_HANDLER(x) \ + if (x) { \ + ecore_event_handler_del(x); \ + x = NULL; \ + } + FREE_HANDLER(_G.handler_border_resize); + FREE_HANDLER(_G.handler_border_move); + FREE_HANDLER(_G.handler_border_add); + FREE_HANDLER(_G.handler_border_remove); + + FREE_HANDLER(_G.handler_border_iconify); + FREE_HANDLER(_G.handler_border_uniconify); + FREE_HANDLER(_G.handler_border_stick); + FREE_HANDLER(_G.handler_border_unstick); + + FREE_HANDLER(_G.handler_desk_show); + FREE_HANDLER(_G.handler_desk_before_show); + FREE_HANDLER(_G.handler_desk_set); +#undef FREE_HANDLER + + +#define ACTION_DEL(act, title, value) \ + if (act) { \ + e_action_predef_name_del(_("Tiling"), _(title)); \ + e_action_del(value); \ + act = NULL; \ + } + ACTION_DEL(_G.act_togglefloat, "Toggle floating", "toggle_floating"); + ACTION_DEL(_G.act_addstack, "Add a stack", "add_stack"); + ACTION_DEL(_G.act_removestack, "Remove a stack", "remove_stack"); + ACTION_DEL(_G.act_tg_stack, "Toggle between rows and columns", "tg_cols_rows"); + ACTION_DEL(_G.act_swap, "Swap a window with an other", "swap"); + ACTION_DEL(_G.act_move, "Move window", "move"); + ACTION_DEL(_G.act_adjusttransitions, "Adjust transitions", + "adjust_transitions"); + ACTION_DEL(_G.act_go, "Focus a particular window", "go"); +#undef ACTION_DEL + + e_configure_registry_item_del("windows/tiling"); + e_configure_registry_category_del("windows"); + + end_special_input(); + + free(tiling_g.config->keyhints); + E_FREE(tiling_g.config); + E_CONFIG_DD_FREE(_G.config_edd); + E_CONFIG_DD_FREE(_G.vdesk_edd); + + tiling_g.module = NULL; + + eina_hash_free(_G.info_hash); + _G.info_hash = NULL; + + eina_hash_free(_G.border_extras); + _G.border_extras = NULL; + + _G.tinfo = NULL; + + return 1; +} + +EAPI int +e_modapi_save(E_Module *m) +{ + e_config_domain_save("module.tiling", _G.config_edd, tiling_g.config); + + return EINA_TRUE; +} +/* }}} */ diff --git a/src/modules/tiling/e_mod_tiling.h b/src/modules/tiling/e_mod_tiling.h new file mode 100644 index 000000000..d9896059b --- /dev/null +++ b/src/modules/tiling/e_mod_tiling.h @@ -0,0 +1,97 @@ +#ifndef E_MOD_TILING_H +#define E_MOD_TILING_H + +#include +#include +#include + +#include + +#include "config.h" + +typedef struct _Config Config; +typedef struct _Tiling_Info Tiling_Info; + +struct tiling_g +{ + E_Module *module; + Config *config; + int log_domain; + const char *default_keyhints; +}; +extern struct tiling_g tiling_g; + +#define ERR(...) EINA_LOG_DOM_ERR(tiling_g.log_domain, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(tiling_g.log_domain, __VA_ARGS__) + +#define TILING_MAX_STACKS 8 + +struct _Config_vdesk +{ + int x, y; + unsigned int zone_num; + int nb_stacks; + int use_rows; +}; + +struct _Config +{ + int tile_dialogs; + int show_titles; + char *keyhints; + Eina_List *vdesks; +}; + +struct _Tiling_Info +{ + /* The desk for which this _Tiling_Info is used. Needed because + * (for example) on e restart all desks are shown on all zones but no + * change events are triggered */ + const E_Desk *desk; + + struct _Config_vdesk *conf; + + /* List of windows which were toggled floating */ + Eina_List *floating_windows; + + Eina_List *stacks[TILING_MAX_STACKS]; + int pos[TILING_MAX_STACKS]; + int size[TILING_MAX_STACKS]; +}; + +struct _E_Config_Dialog_Data +{ + struct _Config config; + Evas_Object *o_zonelist; + Evas_Object *o_desklist; + Evas_Object *osf; + Evas *evas; +}; + +E_Config_Dialog *e_int_config_tiling_module(E_Container *con, + const char *params); + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init(E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save(E_Module *m); + +void change_desk_conf(struct _Config_vdesk *newconf); + +void e_tiling_update_conf(void); + +struct _Config_vdesk * +get_vdesk(Eina_List *vdesks, + int x, + int y, + unsigned int zone_num); + +#define EINA_LIST_IS_IN(_list, _el) \ + (eina_list_data_find(_list, _el) == _el) +#define EINA_LIST_APPEND(_list, _el) \ + _list = eina_list_append(_list, _el) +#define EINA_LIST_REMOVE(_list, _el) \ + _list = eina_list_remove(_list, _el) + +#endif diff --git a/src/modules/tiling/images/arrow_e.png b/src/modules/tiling/images/arrow_e.png new file mode 100644 index 000000000..06b6f291b Binary files /dev/null and b/src/modules/tiling/images/arrow_e.png differ diff --git a/src/modules/tiling/images/arrow_n.png b/src/modules/tiling/images/arrow_n.png new file mode 100644 index 000000000..c5a5de51c Binary files /dev/null and b/src/modules/tiling/images/arrow_n.png differ diff --git a/src/modules/tiling/images/arrow_ne.png b/src/modules/tiling/images/arrow_ne.png new file mode 100644 index 000000000..8c5112de8 Binary files /dev/null and b/src/modules/tiling/images/arrow_ne.png differ diff --git a/src/modules/tiling/images/arrow_nw.png b/src/modules/tiling/images/arrow_nw.png new file mode 100644 index 000000000..92e5656dc Binary files /dev/null and b/src/modules/tiling/images/arrow_nw.png differ diff --git a/src/modules/tiling/images/arrow_s.png b/src/modules/tiling/images/arrow_s.png new file mode 100644 index 000000000..c5a9f06f0 Binary files /dev/null and b/src/modules/tiling/images/arrow_s.png differ diff --git a/src/modules/tiling/images/arrow_se.png b/src/modules/tiling/images/arrow_se.png new file mode 100644 index 000000000..22613e48b Binary files /dev/null and b/src/modules/tiling/images/arrow_se.png differ diff --git a/src/modules/tiling/images/arrow_sw.png b/src/modules/tiling/images/arrow_sw.png new file mode 100644 index 000000000..bfc2aead2 Binary files /dev/null and b/src/modules/tiling/images/arrow_sw.png differ diff --git a/src/modules/tiling/images/arrow_w.png b/src/modules/tiling/images/arrow_w.png new file mode 100644 index 000000000..479bad9bd Binary files /dev/null and b/src/modules/tiling/images/arrow_w.png differ diff --git a/src/modules/tiling/images/module_icon.png b/src/modules/tiling/images/module_icon.png new file mode 100644 index 000000000..328acc9ad Binary files /dev/null and b/src/modules/tiling/images/module_icon.png differ diff --git a/src/modules/tiling/module.desktop.in b/src/modules/tiling/module.desktop.in new file mode 100644 index 000000000..b4220f232 --- /dev/null +++ b/src/modules/tiling/module.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Link +Name=Tiling +Name[fr]=E-pavage +Icon=e-module-tiling +Comment=Positions/resizes your windows tilingly. +Comment[fr]=Place/Redimensionne les fenêtres sans les superposer. +Comment[it]=Posiziona/ridimensiona le finestre affiancandole. +Comment[pt]=Posiciona/ajusta as janelas em mosaicos +X-Enlightenment-ModuleType=core