diff options
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index 20701081..335dae87 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1764,3 +1764,177 @@ int container_squash(struct sway_container *con) { | |||
1764 | } | 1764 | } |
1765 | return change; | 1765 | return change; |
1766 | } | 1766 | } |
1767 | |||
1768 | static void swap_places(struct sway_container *con1, | ||
1769 | struct sway_container *con2) { | ||
1770 | struct sway_container *temp = malloc(sizeof(struct sway_container)); | ||
1771 | temp->pending.x = con1->pending.x; | ||
1772 | temp->pending.y = con1->pending.y; | ||
1773 | temp->pending.width = con1->pending.width; | ||
1774 | temp->pending.height = con1->pending.height; | ||
1775 | temp->width_fraction = con1->width_fraction; | ||
1776 | temp->height_fraction = con1->height_fraction; | ||
1777 | temp->pending.parent = con1->pending.parent; | ||
1778 | temp->pending.workspace = con1->pending.workspace; | ||
1779 | bool temp_floating = container_is_floating(con1); | ||
1780 | |||
1781 | con1->pending.x = con2->pending.x; | ||
1782 | con1->pending.y = con2->pending.y; | ||
1783 | con1->pending.width = con2->pending.width; | ||
1784 | con1->pending.height = con2->pending.height; | ||
1785 | con1->width_fraction = con2->width_fraction; | ||
1786 | con1->height_fraction = con2->height_fraction; | ||
1787 | |||
1788 | con2->pending.x = temp->pending.x; | ||
1789 | con2->pending.y = temp->pending.y; | ||
1790 | con2->pending.width = temp->pending.width; | ||
1791 | con2->pending.height = temp->pending.height; | ||
1792 | con2->width_fraction = temp->width_fraction; | ||
1793 | con2->height_fraction = temp->height_fraction; | ||
1794 | |||
1795 | int temp_index = container_sibling_index(con1); | ||
1796 | if (con2->pending.parent) { | ||
1797 | container_insert_child(con2->pending.parent, con1, | ||
1798 | container_sibling_index(con2)); | ||
1799 | } else if (container_is_floating(con2)) { | ||
1800 | workspace_add_floating(con2->pending.workspace, con1); | ||
1801 | } else { | ||
1802 | workspace_insert_tiling(con2->pending.workspace, con1, | ||
1803 | container_sibling_index(con2)); | ||
1804 | } | ||
1805 | if (temp->pending.parent) { | ||
1806 | container_insert_child(temp->pending.parent, con2, temp_index); | ||
1807 | } else if (temp_floating) { | ||
1808 | workspace_add_floating(temp->pending.workspace, con2); | ||
1809 | } else { | ||
1810 | workspace_insert_tiling(temp->pending.workspace, con2, temp_index); | ||
1811 | } | ||
1812 | |||
1813 | free(temp); | ||
1814 | } | ||
1815 | |||
1816 | static void swap_focus(struct sway_container *con1, | ||
1817 | struct sway_container *con2, struct sway_seat *seat, | ||
1818 | struct sway_container *focus) { | ||
1819 | if (focus == con1 || focus == con2) { | ||
1820 | struct sway_workspace *ws1 = con1->pending.workspace; | ||
1821 | struct sway_workspace *ws2 = con2->pending.workspace; | ||
1822 | enum sway_container_layout layout1 = container_parent_layout(con1); | ||
1823 | enum sway_container_layout layout2 = container_parent_layout(con2); | ||
1824 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | ||
1825 | if (workspace_is_visible(ws2)) { | ||
1826 | seat_set_focus(seat, &con2->node); | ||
1827 | } | ||
1828 | seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1); | ||
1829 | } else if (focus == con2 && (layout1 == L_TABBED | ||
1830 | || layout1 == L_STACKED)) { | ||
1831 | if (workspace_is_visible(ws1)) { | ||
1832 | seat_set_focus(seat, &con1->node); | ||
1833 | } | ||
1834 | seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2); | ||
1835 | } else if (ws1 != ws2) { | ||
1836 | seat_set_focus_container(seat, focus == con1 ? con2 : con1); | ||
1837 | } else { | ||
1838 | seat_set_focus_container(seat, focus); | ||
1839 | } | ||
1840 | } else { | ||
1841 | seat_set_focus_container(seat, focus); | ||
1842 | } | ||
1843 | |||
1844 | if (root->fullscreen_global) { | ||
1845 | seat_set_focus(seat, | ||
1846 | seat_get_focus_inactive(seat, &root->fullscreen_global->node)); | ||
1847 | } | ||
1848 | } | ||
1849 | |||
1850 | void container_swap(struct sway_container *con1, struct sway_container *con2) { | ||
1851 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { | ||
1852 | return; | ||
1853 | } | ||
1854 | if (!sway_assert(!container_has_ancestor(con1, con2) | ||
1855 | && !container_has_ancestor(con2, con1), | ||
1856 | "Cannot swap ancestor and descendant")) { | ||
1857 | return; | ||
1858 | } | ||
1859 | |||
1860 | sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu", | ||
1861 | con1->node.id, con2->node.id); | ||
1862 | |||
1863 | bool scratch1 = con1->scratchpad; | ||
1864 | bool hidden1 = container_is_scratchpad_hidden(con1); | ||
1865 | bool scratch2 = con2->scratchpad; | ||
1866 | bool hidden2 = container_is_scratchpad_hidden(con2); | ||
1867 | if (scratch1) { | ||
1868 | if (hidden1) { | ||
1869 | root_scratchpad_show(con1); | ||
1870 | } | ||
1871 | root_scratchpad_remove_container(con1); | ||
1872 | } | ||
1873 | if (scratch2) { | ||
1874 | if (hidden2) { | ||
1875 | root_scratchpad_show(con2); | ||
1876 | } | ||
1877 | root_scratchpad_remove_container(con2); | ||
1878 | } | ||
1879 | |||
1880 | enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode; | ||
1881 | if (fs1) { | ||
1882 | container_fullscreen_disable(con1); | ||
1883 | } | ||
1884 | enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode; | ||
1885 | if (fs2) { | ||
1886 | container_fullscreen_disable(con2); | ||
1887 | } | ||
1888 | |||
1889 | struct sway_seat *seat = input_manager_current_seat(); | ||
1890 | struct sway_container *focus = seat_get_focused_container(seat); | ||
1891 | struct sway_workspace *vis1 = | ||
1892 | output_get_active_workspace(con1->pending.workspace->output); | ||
1893 | struct sway_workspace *vis2 = | ||
1894 | output_get_active_workspace(con2->pending.workspace->output); | ||
1895 | if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" | ||
1896 | "workspace. This should not happen")) { | ||
1897 | return; | ||
1898 | } | ||
1899 | |||
1900 | char *stored_prev_name = NULL; | ||
1901 | if (seat->prev_workspace_name) { | ||
1902 | stored_prev_name = strdup(seat->prev_workspace_name); | ||
1903 | } | ||
1904 | |||
1905 | swap_places(con1, con2); | ||
1906 | |||
1907 | if (!workspace_is_visible(vis1)) { | ||
1908 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); | ||
1909 | } | ||
1910 | if (!workspace_is_visible(vis2)) { | ||
1911 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); | ||
1912 | } | ||
1913 | |||
1914 | swap_focus(con1, con2, seat, focus); | ||
1915 | |||
1916 | if (stored_prev_name) { | ||
1917 | free(seat->prev_workspace_name); | ||
1918 | seat->prev_workspace_name = stored_prev_name; | ||
1919 | } | ||
1920 | |||
1921 | if (scratch1) { | ||
1922 | root_scratchpad_add_container(con2, NULL); | ||
1923 | if (!hidden1) { | ||
1924 | root_scratchpad_show(con2); | ||
1925 | } | ||
1926 | } | ||
1927 | if (scratch2) { | ||
1928 | root_scratchpad_add_container(con1, NULL); | ||
1929 | if (!hidden2) { | ||
1930 | root_scratchpad_show(con1); | ||
1931 | } | ||
1932 | } | ||
1933 | |||
1934 | if (fs1) { | ||
1935 | container_set_fullscreen(con2, fs1); | ||
1936 | } | ||
1937 | if (fs2) { | ||
1938 | container_set_fullscreen(con1, fs2); | ||
1939 | } | ||
1940 | } | ||