summaryrefslogtreecommitdiff
path: root/devilspie/script_functions.c
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2024-11-24 06:57:05 -0600
committerJeff Carr <[email protected]>2024-11-24 06:57:05 -0600
commitcfd6fdadd756edccd0115563d759e37306b57e9c (patch)
tree4c4e040ef66da9944c3e1b7a262e0f258668b329 /devilspie/script_functions.c
day 1v0.0.0
Diffstat (limited to 'devilspie/script_functions.c')
-rw-r--r--devilspie/script_functions.c2659
1 files changed, 2659 insertions, 0 deletions
diff --git a/devilspie/script_functions.c b/devilspie/script_functions.c
new file mode 100644
index 0000000..240d582
--- /dev/null
+++ b/devilspie/script_functions.c
@@ -0,0 +1,2659 @@
+/**
+ * This file is part of devilspie2
+ * Copyright (C) 2011-2019 Andreas Rönnquist
+ * Copyright (C) 2019-2021 Darren Salt
+ *
+ * devilspie2 is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * devilspie2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with devilspie2.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "glib.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+#include <locale.h>
+
+#include <limits.h>
+
+#include "intl.h"
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include <X11/extensions/Xrandr.h>
+
+#if (GTK_MAJOR_VERSION >= 3)
+#define HAVE_GTK3
+#endif
+
+
+#include "compat.h"
+
+#include "script_functions.h"
+
+#include "script.h"
+
+#include "xutils.h"
+
+#include "error_strings.h"
+
+#define DEPRECATED() fprintf(stderr, "warning: deprecated function %s called\n", __func__ + 2);
+
+/**
+ *
+ */
+WnckWindow *current_window = NULL;
+
+static Bool current_time_cb(Display *display, XEvent *xevent, XPointer arg)
+{
+ Window wnd = GPOINTER_TO_UINT(arg);
+
+ if (xevent->type == PropertyNotify &&
+ xevent->xproperty.window == wnd &&
+ xevent->xproperty.atom == my_wnck_atom_get("WM_NAME"))
+ return True;
+
+ return False;
+}
+
+/**
+ * Get current X11 timestamp.
+ *
+ * Unfortunately, gtk_get_current_event_time() does not work here
+ * because we cannot assume we are inside an event.
+ *
+ * Getting this timestamp is tricky. According to a comment in the ICCCM
+ * specification (https://tronche.com/gui/x/icccm/sec-2.html#s-2.1):
+ *
+ * A zero-length append to a property is a way to obtain a
+ * timestamp for this purpose; the timestamp is in the
+ * corresponding PropertyNotify event.
+ *
+ * So here we are zero-length appending to the "WM_NAME" property.
+ */
+static guint32 current_time(void)
+{
+ WnckWindow *window;
+ gulong wnd;
+ Display *dpy;
+ Atom prop;
+ XEvent xevent;
+
+ window = get_current_window();
+ if (!window)
+ return GDK_CURRENT_TIME;
+
+ dpy = gdk_x11_get_default_xdisplay();
+ wnd = wnck_window_get_xid(window);
+ prop = my_wnck_atom_get("WM_NAME");
+ XChangeProperty(dpy, wnd, prop, XA_STRING, 8, PropModeAppend, NULL, 0);
+
+ /* Wait for the event to succeed */
+ XIfEvent(dpy, &xevent, current_time_cb, GUINT_TO_POINTER(wnd));
+ return xevent.xproperty.time;
+}
+
+
+/**
+ * Check for the correct parameter count.
+ * Failure will log a lua error and return False.
+ * Success returns True.
+ */
+static Bool check_param_count(lua_State *lua, const char *funcname, int expected)
+{
+ int top = lua_gettop(lua);
+ gchar* error_message;
+
+ if (top != expected) {
+ error_message = num_indata_expected_errors[expected];
+ if (error_message == NULL) {
+ error_message = failed_string;
+ }
+ luaL_error(lua, "%s: %s", funcname, error_message);
+ return False;
+ }
+ return True;
+}
+
+/**
+ * Check for the correct parameter count, one of two expected values.
+ * Failure will log a lua error and return False.
+ * Success returns True.
+ */
+static Bool check_param_counts(lua_State *lua, const char *funcname, int expected1, int expected2)
+{
+ int top = lua_gettop(lua);
+ gchar* error_message;
+
+ if (top != expected1 && top != expected2) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ error_message = g_strdup_printf(n_or_m_indata_expected_error, expected1, expected2);
+#pragma GCC diagnostic pop
+ luaL_error(lua, "%s: %s", funcname, error_message);
+ g_free(error_message);
+ return False;
+ }
+ return True;
+}
+
+/**
+ * Check for the correct parameter count in a range of expected values.
+ * Failure will log a lua error and return False.
+ * Success returns True.
+ */
+static Bool check_param_counts_range(lua_State *lua, char *funcname, int expected_min, int expected_max)
+{
+ int top = lua_gettop(lua);
+ gchar* error_message;
+
+ if (top < expected_min || top > expected_max) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ error_message = g_strdup_printf(n_to_m_indata_expected_error, expected_min, expected_max);
+#pragma GCC diagnostic pop
+ luaL_error(lua, "%s: %s", funcname, error_message);
+ g_free(error_message);
+ return False;
+ }
+ return True;
+}
+
+static gboolean default_use_utf8 = False;
+
+gboolean c_use_utf8(lua_State *lua)
+{
+ if (!check_param_counts(lua, "use_utf8", 0, 1)) {
+ return 0;
+ }
+
+ gboolean v = default_use_utf8;
+ int top = lua_gettop(lua);
+
+ if (top) {
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "use_utf8: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+ v = (gboolean)(value);
+ }
+
+ lua_pushboolean(lua, default_use_utf8);
+ default_use_utf8 = v;
+ return 1;
+}
+
+static gboolean adjusting_for_decoration = FALSE;
+
+int c_set_adjust_for_decoration(lua_State *lua)
+{
+ if (!check_param_counts(lua, "set_adjust_for_decoration", 0, 1)) {
+ return 0;
+ }
+
+ gboolean v = TRUE;
+
+ if (lua_gettop(lua)) {
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_adjust_for_decoration: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+ v = (gboolean)(value);
+ }
+
+ adjusting_for_decoration = v;
+ return 0;
+}
+
+
+/**
+ * returns the window name
+ */
+int c_get_window_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_name", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ const char *test = window ? wnck_window_get_name(window) : "";
+
+ lua_pushstring(lua, test);
+
+ // one item returned (the window name as a string)
+ return 1;
+}
+
+
+/**
+ * c_get_window_name always returns a string, even if a window hasn't
+ * got a name - use this function to determine if a window really has
+ * a name or not.
+ * returns a boolean true or false
+ */
+int c_get_window_has_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_has_name", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gboolean has_name = window ? wnck_window_has_name(window) : FALSE;
+
+ lua_pushboolean(lua, has_name);
+
+ return 1;
+}
+
+
+/**
+ * Internal code for calculating the new position of the window
+ * Returns -1 on parameter error, +1 (TRUE) on success (or if emulating), else 0 (FALSE)
+ */
+static int do_set_window_position_internal(lua_State *restrict lua, const char *const fn, int *restrict px, int *restrict py, gboolean with_size)
+{
+ int monitor = with_size ? 5 : 3;
+ if (!check_param_counts(lua, fn, monitor - 1, monitor)) {
+ return -1;
+ }
+
+ int top = lua_gettop(lua);
+
+ for (int i = 1; i <= top; ++i)
+ if (lua_type(lua, i) != LUA_TNUMBER) {
+ luaL_error(lua, "%s: %s", fn, number_expected_as_indata_error);
+ return -1;
+ }
+
+ *px = lua_tonumber(lua, 1);
+ *py = lua_tonumber(lua, 2);
+
+ if (top == monitor) {
+ monitor = lua_tonumber (lua, monitor) - 1;
+ if (monitor < MONITOR_ALL || monitor >= get_monitor_count())
+ monitor = 0; // FIXME: primary monitor; show warning?
+ } else
+ monitor = MONITOR_NONE;
+
+ if (devilspie2_emulate)
+ return TRUE;
+
+ WnckWindow *window = get_current_window();
+ if (!window)
+ return FALSE;
+
+ if (monitor != MONITOR_NONE) {
+ /* +ve x: relative to left
+ * -ve x: relative to right (bitwise NOT)
+ * +ve y: relative to top
+ * -ve y: relative to bottom (bitwise NOT)
+ */
+ GdkRectangle bounds, geom;
+ wnck_window_get_geometry(window, &geom.x, &geom.y, &geom.width, &geom.height);
+ monitor = get_monitor_or_workspace_geometry(monitor, window, &bounds);
+ if (monitor == MONITOR_NONE)
+ return FALSE;
+
+ if (*px < 0)
+ *px = bounds.x + bounds.width - ~*px - geom.width;
+ else
+ *px += bounds.x;
+ if (*py < 0)
+ *py = bounds.y + bounds.height - ~*py - geom.height;
+ else
+ *py += bounds.y;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Set the Window Geometry
+ * set_window_geometry(x,y,xsize,ysize,[monitor_index]);
+ */
+int c_set_window_geometry(lua_State *lua)
+{
+ int x, y;
+ int ret = do_set_window_position_internal(lua, "set_window_geometry", &x, &y, TRUE);
+
+ if (ret < 0)
+ return 0;
+ else if (ret > 0) {
+ int xsize = lua_tonumber(lua, 3);
+ int ysize = lua_tonumber(lua, 4);
+ WnckWindow *window = get_current_window();
+ if (window) {
+ set_window_geometry(window, x, y, xsize, ysize, adjusting_for_decoration);
+ }
+ }
+
+ lua_pushboolean(lua, ret);
+ return 1;
+}
+
+
+/**
+ * Set the Window Geometry2
+ * set_window_geometry2(x,y,xsize,ysize,[monitor_index]);
+ */
+int c_set_window_geometry2(lua_State *lua)
+{
+ int x, y;
+ int ret = do_set_window_position_internal(lua, "set_window_geometry2", &x, &y, TRUE);
+
+ if (ret < 0)
+ return 0;
+ else if (ret > 0) {
+ int xsize = lua_tonumber(lua, 3);
+ int ysize = lua_tonumber(lua, 4);
+ WnckWindow *window = get_current_window();
+ if (window) {
+ XMoveResizeWindow(gdk_x11_get_default_xdisplay(),
+ wnck_window_get_xid(window),
+ x, y,
+ xsize, ysize);
+ }
+ }
+
+ lua_pushboolean(lua, ret);
+ return 1;
+}
+
+
+/**
+ * Set the position of the window
+ */
+int c_set_window_position(lua_State *lua)
+{
+ int x, y;
+ int ret = do_set_window_position_internal(lua, "set_window_position", &x, &y, FALSE);
+
+ if (ret < 0)
+ return 0;
+ else if (ret > 0) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ if (adjusting_for_decoration)
+ adjust_for_decoration(window, &x, &y, NULL, NULL);
+ wnck_window_set_geometry(window,
+ WNCK_WINDOW_GRAVITY_CURRENT,
+ WNCK_WINDOW_CHANGE_X + WNCK_WINDOW_CHANGE_Y,
+ x, y, -1, -1);
+ }
+ }
+
+ lua_pushboolean(lua, ret);
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_set_window_position2(lua_State *lua)
+{
+ int x, y;
+ int ret = do_set_window_position_internal(lua, "set_window_position2", &x, &y, FALSE);
+
+ if (ret < 0)
+ return 0;
+ else if (ret > 0) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ XMoveWindow(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
+ wnck_window_get_xid(window),
+ x, y);
+ }
+ }
+
+ lua_pushboolean(lua, ret);
+ return 1;
+}
+
+
+/**
+ * Sets the size of the window
+ */
+int c_set_window_size(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_window_size", 2)) {
+ return 0;
+ }
+
+ int type1 = lua_type(lua, 1);
+ int type2 = lua_type(lua, 2);
+
+ if ((type1 != LUA_TNUMBER) || (type2 != LUA_TNUMBER)) {
+ luaL_error(lua,"set_window_size: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ int x = lua_tonumber(lua,1);
+ int y = lua_tonumber(lua,2);
+
+ if (!devilspie2_emulate) {
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+
+ devilspie2_error_trap_push();
+ if (adjusting_for_decoration)
+ adjust_for_decoration (window, NULL, NULL, &x, &y);
+ wnck_window_set_geometry(window,
+ WNCK_WINDOW_GRAVITY_CURRENT,
+ WNCK_WINDOW_CHANGE_WIDTH + WNCK_WINDOW_CHANGE_HEIGHT,
+ -1, -1, x, y);
+
+ if (devilspie2_error_trap_pop()) {
+ gchar *temperror=
+ g_strdup_printf("set_window_size: %s", failed_string);
+ g_printerr("%s", temperror);
+
+ g_free(temperror);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+#define NUM_STRUTS 12
+static gulong *get_default_struts(Display *dpy)
+{
+ int screen = DefaultScreen(dpy);
+ int width, height;
+
+ static gulong struts[NUM_STRUTS];
+ memset (struts, 0, sizeof(struts));
+#ifdef HAVE_XRANDR
+ // If we have xrandr (we probably do), get the maximum screen size
+ int x; // throwaway
+ XRRGetScreenSizeRange (dpy, RootWindow(dpy, screen),
+ &x, &x, &width, &height);
+#else
+ // Otherwise, fall back to the current size
+ width = DisplayWidth(dpy, screen);
+ height = DisplayHeight(dpy, screen);
+#endif
+ struts[5] = struts[7] = height;
+ struts[9] = struts[11] = width;
+
+ return struts;
+}
+
+/**
+ * Sets the window strut
+ */
+int c_set_window_strut(lua_State *lua)
+{
+ int top = lua_gettop(lua);
+
+ if (top < 4) {
+ luaL_error(lua,"set_window_strut: %s", at_least_four_indata_expected_error);
+ return 0;
+ }
+
+ if (top > NUM_STRUTS)
+ top = NUM_STRUTS;
+
+ if (!devilspie2_emulate) {
+ Display *dpy = gdk_x11_get_default_xdisplay();
+
+ gulong *struts = get_default_struts(dpy);
+ for (int i = 0; i < top; i++) {
+ struts[i] = lua_tonumber(lua, i + 1);
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ XChangeProperty(dpy,
+ wnck_window_get_xid(window),
+ XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False), XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)struts,
+ NUM_STRUTS);
+ XSync(dpy, False);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Gets the window strut
+ */
+int c_get_window_strut(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_strut", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (!window)
+ return 0;
+
+ Display *dpy = gdk_x11_get_default_xdisplay();
+ gulong *struts = NULL;
+ int len = 0;
+
+ gboolean ret = my_wnck_get_cardinal_list (wnck_window_get_xid(window),
+ XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False),
+ &struts, &len);
+ /* if that fails, try reading the older, deprecated property */
+ if (!ret)
+ ret = my_wnck_get_cardinal_list (wnck_window_get_xid(window),
+ XInternAtom(dpy, "_NET_WM_STRUT", False),
+ &struts, &len);
+
+ if (len) {
+ int i;
+ if (len > NUM_STRUTS)
+ len = NUM_STRUTS;
+
+ lua_createtable(lua, NUM_STRUTS, 0);
+ for (i = 0; i < len; ++i) {
+ lua_pushinteger(lua, struts[i]);
+ lua_rawseti(lua, -2, i + 1);
+ }
+ g_free(struts);
+
+ // pad out with default values if necessary
+ if (len < NUM_STRUTS) {
+ struts = get_default_struts(dpy);
+ for (; i < NUM_STRUTS; ++i) {
+ lua_pushinteger(lua, struts[i]);
+ lua_rawseti(lua, -2, i + 1);
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Sets the window on top of all others and locks it "always on top"
+ */
+int c_make_always_on_top(lua_State *lua)
+{
+ if (!check_param_count(lua, "make_always_on_top", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ wnck_window_make_above(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * sets the window on top of all the others
+ */
+int c_set_on_top(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_on_top", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window)
+ XRaiseWindow(gdk_x11_get_default_xdisplay(), wnck_window_get_xid(window));
+ }
+
+ return 0;
+}
+
+
+/**
+ * sets the window below all the others
+ */
+int c_set_on_bottom(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_on_bottom", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window)
+ XLowerWindow(gdk_x11_get_default_xdisplay(), wnck_window_get_xid(window));
+ }
+
+ return 0;
+}
+
+
+/**
+ * returns the application name
+ */
+int c_get_application_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_application_name", 0)) {
+ return 0;
+ }
+
+ const char *application_name = "";
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ WnckApplication *application=
+ wnck_window_get_application(get_current_window());
+ if (application)
+ application_name = wnck_application_get_name(application);
+ }
+
+ // one item returned - the application name as a string.
+ lua_pushstring(lua, application_name);
+
+ return 1;
+}
+
+
+/**
+ * lua_Bprint from http://www.lua.org/source/5.1/lbaselib.c.html
+ * but with the change that fputs is only called if devilspie2_debug is
+ * set to TRUE
+ */
+int c_debug_print(lua_State *lua)
+{
+ int n = lua_gettop(lua); /* number of arguments */
+ lua_getglobal(lua, "tostring");
+
+ for (int i = 1; i <= n; i++) {
+ lua_pushvalue(lua, -1); /* function to be called */
+ lua_pushvalue(lua, i); /* value to print */
+ lua_call(lua, 1, 1);
+
+ const char *s = lua_tostring(lua, -1); /* get result */
+ if (s == NULL)
+ return luaL_error(lua, "'tostring' must return a string to 'print'");
+ if (i > 1) {
+ if (devilspie2_debug) fputs("\t", stdout);
+ }
+ if (devilspie2_debug) fputs(s, stdout);
+ lua_pop(lua, 1); /* pop result */
+ }
+ if (devilspie2_debug) {
+ fputs("\n", stdout);
+ fflush(stdout);
+ }
+
+ return 0;
+}
+
+
+/**
+ * "Shades" the window
+ */
+int c_shade(lua_State *lua)
+{
+ if (!check_param_count(lua, "shade", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ wnck_window_shade(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * "Unshades" the window
+ */
+int c_unshade(lua_State *lua)
+{
+ if (!check_param_count(lua, "unshade", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ wnck_window_unshade(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Minimizes the window
+ */
+int c_minimize(lua_State *lua)
+{
+ if (!check_param_count(lua, "minimize", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ wnck_window_minimize(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * unminimizes window
+ */
+int c_unminimize(lua_State *lua)
+{
+ if (!check_param_count(lua, "unminimize", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ wnck_window_unminimize (window, current_time());
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * sets the window that the scripts are affecting
+ */
+void set_current_window(WnckWindow *window)
+{
+ current_window=window;
+}
+
+
+/**
+ * gets the window that the scripts are affecting
+ */
+WnckWindow *get_current_window()
+{
+ return current_window;
+}
+
+
+/**
+ * Decorates a window
+ */
+int c_undecorate_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "undecorate_window", 0)) {
+ return 0;
+ }
+
+ gboolean result = TRUE;
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ gulong xid = wnck_window_get_xid(window);
+
+ if (!undecorate_window(xid)) {
+ result=FALSE;
+ }
+ }
+ }
+
+ lua_pushboolean(lua,result);
+
+ return 1;
+}
+
+
+/**
+ * undecorates a window
+ */
+int c_decorate_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "decorate_window", 0)) {
+ return 0;
+ }
+
+ gboolean result = TRUE;
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ gulong xid = wnck_window_get_xid(window);
+
+ if (!decorate_window(xid)) {
+ result=FALSE;
+ }
+ }
+ }
+
+ lua_pushboolean(lua,result);
+
+ return 1;
+}
+
+
+
+/**
+ * Checks if a window is decorated
+ */
+int c_get_window_is_decorated(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_is_decorated", 0)) {
+ return 0;
+ }
+
+ gboolean result = TRUE;
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ result = get_decorated(wnck_window_get_xid(window));
+ }
+ }
+
+ lua_pushboolean(lua,result);
+
+ return 1;
+}
+
+/**
+ Given a workspace name, perform a linear, case-sensitive search for
+ a workspace with with said name.
+
+ Returns the first found or -1
+ */
+int find_workspace_with_name(gchar *in_workspace_name, WnckWindow *window){
+ if(window == NULL) {
+ window = get_current_window();
+ }
+ if(window == NULL || in_workspace_name == NULL || strlen(in_workspace_name) <= 0) {
+ return -1;
+ }
+
+ WnckScreen *screen = wnck_window_get_screen(window);
+
+ for (int space = 0; space < wnck_screen_get_workspace_count(screen); space++) {
+ WnckWorkspace *workspace = wnck_screen_get_workspace(screen, space);
+ if(workspace == NULL) //Theoretically possible
+ continue;
+ if(0 == g_strcmp0(in_workspace_name, wnck_workspace_get_name(workspace))){
+ return space;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Move a window to a specific workspace
+ */
+int c_set_window_workspace(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_window_workspace", 1)) {
+ return 0;
+ }
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TNUMBER && type != LUA_TSTRING ) {
+ luaL_error(lua, "set_window_workspace: %s",
+ number_or_string_expected_as_indata_error);
+ return 0;
+ }
+
+ int workspace_idx0 = -1;
+ gchar *workspace_name = NULL;
+
+ switch (type) {
+ case LUA_TNUMBER:
+ workspace_idx0 = lua_tonumber(lua, 1) - 1;
+ break;
+ case LUA_TSTRING:
+ workspace_name = (gchar*)lua_tostring(lua, 1);
+ workspace_idx0 = find_workspace_with_name(workspace_name, get_current_window());
+ if(workspace_idx0 == -1) {
+ g_warning(_("A workspace with the name '%s' does not exist!"), workspace_name);
+ }
+ break;
+ default: break;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (window && workspace_idx0 > -1) {
+ WnckScreen *screen = wnck_window_get_screen(window);
+ WnckWorkspace *workspace = wnck_screen_get_workspace(screen, workspace_idx0);
+
+ if (!workspace) {
+ g_warning(_("Workspace number %d does not exist!"), workspace_idx0+1);
+ }
+ if (!devilspie2_emulate) {
+ wnck_window_move_to_workspace(window, workspace);
+ }
+ }
+
+ lua_pushboolean(lua,TRUE);
+
+ return 1;
+}
+
+
+/**
+ * Makes a workspace the active one
+ */
+int c_change_workspace(lua_State *lua)
+{
+ if (!check_param_count(lua, "change_workspace", 1)) {
+ return 0;
+ }
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TNUMBER && type != LUA_TSTRING) {
+ luaL_error(lua,"change_workspace: %s", number_or_string_expected_as_indata_error);
+ return 0;
+ }
+
+ int workspace_idx0 = -1;
+ gchar *workspace_name = NULL;
+
+ switch (type) {
+ case LUA_TNUMBER:
+ workspace_idx0 = lua_tonumber(lua, 1) - 1;
+ break;
+ case LUA_TSTRING:
+ workspace_name = (gchar*)lua_tostring(lua, 1);
+ workspace_idx0 = find_workspace_with_name(workspace_name, get_current_window());
+ if(workspace_idx0 == -1) {
+ g_warning(_("A workspace with the name '%s' does not exist!"), workspace_name);
+ }
+ break;
+ default: break;
+ }
+
+ WnckWindow *window = get_current_window();
+ if (window && workspace_idx0 > -1) {
+ WnckScreen *screen = wnck_window_get_screen(window);
+ WnckWorkspace *workspace = wnck_screen_get_workspace(screen, workspace_idx0);
+
+ if (!workspace) {
+ g_warning(_("Workspace number %d does not exist!"), workspace_idx0+1);
+ }
+
+ gint64 timestamp = g_get_real_time();
+ if (!devilspie2_emulate) {
+ wnck_workspace_activate(workspace, timestamp / 1000000);
+ }
+ }
+
+ lua_pushboolean(lua, TRUE);
+
+ return 1;
+}
+
+
+/**
+ * Return workspace count
+ */
+int c_get_workspace_count(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_workspace_count", 0)) {
+ return 0;
+ }
+
+ int count = 0;
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ WnckScreen *screen = wnck_window_get_screen(window);
+ count = wnck_screen_get_workspace_count(screen);
+ }
+
+ lua_pushinteger(lua, count);
+
+ return 1;
+}
+
+
+/**
+ * Unmaximize window
+ */
+int c_unmaximize(lua_State *lua)
+{
+ if (!check_param_count(lua, "unmaximize", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_unmaximize(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Maximize Window
+ */
+int c_maximize(lua_State *lua)
+{
+ if (!check_param_count(lua, "maximize", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_maximize(window);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Maximize Window Vertically
+ */
+int c_maximize_vertically(lua_State *lua)
+{
+ if (!check_param_count(lua, "maximize_vertically", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_maximize_vertically(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Maximize the window horizontally
+ */
+int c_maximize_horizontally(lua_State *lua)
+{
+ if (!check_param_count(lua, "maximize_horizontally", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_maximize_horizontally(window);
+ }
+ }
+
+ return 0;
+}
+
+int c_maximize_horisontally(lua_State *lua)
+{
+ DEPRECATED();
+ return c_maximize_horizontally(lua);
+}
+
+
+/**
+ * Pins the window
+ */
+int c_pin_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "pin_window", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_pin(window);
+ }
+ }
+
+ return 0;
+}
+
+
+
+/**
+ * Unpin the window
+ */
+int c_unpin_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "unpin_window", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_unpin(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Sticks the window
+ */
+int c_stick_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "stick_window", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_stick(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Unstick the window
+ */
+int c_unstick_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "unstick_window", 0)) {
+ return 0;
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_unstick(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * return the geometry of the current window to the Lua script
+ */
+int c_get_window_geometry(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_geometry", 0)) {
+ return 0;
+ }
+
+ int x = 0, y = 0, width = 0, height = 0;
+
+ WnckWindow *window = get_current_window();
+ if (window)
+ {
+ wnck_window_get_geometry(window, &x, &y, &width, &height);
+ }
+
+ lua_pushinteger(lua, x);
+ lua_pushinteger(lua, y);
+ lua_pushinteger(lua, width);
+ lua_pushinteger(lua, height);
+
+ return 4;
+}
+
+
+/**
+ * return the client geometry of the current window to the Lua script
+ * this is excluding the window manager frame
+ */
+int c_get_window_client_geometry(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_client_geometry", 0)) {
+ return 0;
+ }
+
+ int x = 0, y = 0, width = 0, height = 0;
+
+ WnckWindow *window = get_current_window();
+ if (window)
+ {
+ wnck_window_get_client_window_geometry(window, &x, &y, &width, &height);
+ }
+
+ lua_pushinteger(lua, x);
+ lua_pushinteger(lua, y);
+ lua_pushinteger(lua, width);
+ lua_pushinteger(lua, height);
+
+ return 4;
+}
+
+
+/**
+ * return the window frame extents
+ */
+int c_get_window_frame_extents(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_frame_extents", 0)) {
+ return 0;
+ }
+
+ int left = 0, right = 0, top = 0, bottom = 0;
+
+ WnckWindow *window = get_current_window();
+ if (window) {
+ // Order of preference:
+ // _NET_FRAME_EXTENTS
+ // Calculation from geometries
+
+ Display *dpy = gdk_x11_get_default_xdisplay();
+ gulong *extents = 0;
+ int len = 0;
+
+ my_wnck_get_cardinal_list (wnck_window_get_xid(window),
+ XInternAtom(dpy, "_NET_FRAME_EXTENTS", False),
+ &extents, &len);
+ if (len >= 4) {
+ // _NET_FRAME_EXTENTS
+ left = extents[0];
+ right = extents[1];
+ top = extents[2];
+ bottom = extents[3];
+ g_free(extents);
+ }
+ else {
+ // Calculation from geometries
+ int frame[4] = {}, client[4] = {};
+
+ wnck_window_get_geometry(window, frame, frame + 1, frame + 2, frame + 3);
+ wnck_window_get_client_window_geometry(window, client, client + 1, client + 2, client + 3);
+ left = client[0] - frame[0];
+ right = frame[2] - client[2] - left;
+ top = client[1] - frame[1];
+ bottom = frame[3] - client[3] - top;
+ }
+ }
+
+ lua_pushinteger(lua, left);
+ lua_pushinteger(lua, right);
+ lua_pushinteger(lua, top);
+ lua_pushinteger(lua, bottom);
+
+ return 4;
+}
+
+
+/**
+ *
+ */
+int c_set_skip_tasklist(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_skip_tasklist", 1)) {
+ return 0;
+ }
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_skip_tasklist: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+
+ gboolean skip_tasklist = (gboolean)(value);
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_set_skip_tasklist(window, skip_tasklist);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_set_skip_pager(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_skip_pager", 1)) {
+ return 0;
+ }
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_skip_pager: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+
+ gboolean skip_pager = (gboolean)(value);
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ wnck_window_set_skip_pager(window, skip_pager);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_get_window_is_maximized(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_is_maximized", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gboolean is_maximized = window ? wnck_window_is_maximized(window) : FALSE;
+
+ lua_pushboolean(lua, is_maximized);
+
+ return 1;
+}
+
+/**
+ *
+ */
+int c_get_window_is_maximized_vertically(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_is_maximized_vertically", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gboolean is_vertically_maximized = window ? wnck_window_is_maximized_vertically(window) : FALSE;
+
+ lua_pushboolean(lua, is_vertically_maximized);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_get_window_is_maximized_horizontally(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_is_maximized_horizontally", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gboolean is_horizontally_maximized = window ? wnck_window_is_maximized_horizontally(window) : FALSE;
+
+ lua_pushboolean(lua, is_horizontally_maximized);
+
+ return 1;
+}
+
+int c_get_window_is_maximized_horisontally(lua_State *lua)
+{
+ DEPRECATED();
+ return c_get_window_is_maximized_horizontally(lua);
+}
+
+
+/**
+ *
+ */
+int c_get_window_is_pinned(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_is_pinned", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gboolean is_pinned = window ? wnck_window_is_pinned(window) : FALSE;
+
+ lua_pushboolean(lua, is_pinned);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_set_window_above(lua_State *lua)
+{
+ if (!check_param_counts(lua, "set_window_above", 0, 1)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+ gboolean set_above = TRUE;
+
+ if (top == 1)
+ {
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_window_above: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+ set_above = (gboolean)(value);
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ if (set_above)
+ wnck_window_make_above(window);
+ else
+ wnck_window_unmake_above(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_set_window_below(lua_State *lua)
+{
+ if (!check_param_counts(lua, "set_window_below", 0, 1)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+ gboolean set_below = TRUE;
+
+ if (top == 1)
+ {
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_window_below: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ int value = lua_toboolean(lua, 1);
+ set_below = (gboolean)(value);
+ }
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ if (set_below)
+ wnck_window_make_below(window);
+ else
+ wnck_window_unmake_below(window);
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_get_window_type(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_type", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ const char *window_type_string;
+
+ if (window) {
+ WnckWindowType window_type = wnck_window_get_window_type(window);
+
+ switch (window_type) {
+ case WNCK_WINDOW_NORMAL:
+ window_type_string = "WINDOW_TYPE_NORMAL";
+ break;
+ case WNCK_WINDOW_DESKTOP:
+ window_type_string = "WINDOW_TYPE_DESKTOP";
+ break;
+ case WNCK_WINDOW_DOCK:
+ window_type_string = "WINDOW_TYPE_DOCK";
+ break;
+ case WNCK_WINDOW_DIALOG:
+ window_type_string = "WINDOW_TYPE_DIALOG";
+ break;
+ case WNCK_WINDOW_TOOLBAR:
+ window_type_string = "WINDOW_TYPE_TOOLBAR";
+ break;
+ case WNCK_WINDOW_MENU:
+ window_type_string = "WINDOW_TYPE_MENU";
+ break;
+ case WNCK_WINDOW_UTILITY:
+ window_type_string = "WINDOW_TYPE_UTILITY";
+ break;
+ case WNCK_WINDOW_SPLASHSCREEN:
+ window_type_string = "WINDOW_TYPE_SPLASHSCREEN";
+ break;
+ default:
+ window_type_string = "WINDOW_TYPE_UNRECOGNIZED";
+ };
+ } else {
+ window_type_string = "WINDOW_ERROR";
+ }
+
+ lua_pushstring(lua, window_type_string);
+
+ return 1;
+}
+
+
+/**
+ * c_get_class_instance_name
+ * Only available on libwnck 3+
+ */
+int c_get_class_instance_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_class_instance_name", 0)) {
+ return 0;
+ }
+
+#ifdef HAVE_GTK3
+ WnckWindow *window = get_current_window();
+ const char *class_instance_name = window ? wnck_window_get_class_instance_name(window) : "";
+
+ // one item returned - the window class instance name as a string.
+ lua_pushstring(lua, class_instance_name);
+#else
+ lua_pushnil(lua);
+#endif
+ return 1;
+}
+
+/**
+ * c_get_class_group_name
+ * Only available on libwnck 3+
+ */
+int c_get_class_group_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_class_group_name", 0)) {
+ return 0;
+ }
+
+#ifdef HAVE_GTK3
+ WnckWindow *window = get_current_window();
+ const char *class_group_name = window ? wnck_window_get_class_group_name(window) : "";
+
+ // one item returned - the window class instance name as a string.
+ lua_pushstring(lua, class_group_name);
+#else
+ lua_pushnil(lua);
+#endif
+ return 1;
+}
+
+
+/**
+ *
+ */
+static int c_get_window_property_internal(lua_State *lua, const char *func, gboolean report)
+{
+ if (!check_param_count(lua, "get_window_property", 1)) {
+ return 0;
+ }
+
+ // gchar *property=
+ int ret = 0;
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TSTRING) {
+ luaL_error(lua, "%s: %s", func, string_expected_as_indata_error);
+ return 0;
+ }
+
+ const gchar *value = lua_tostring(lua, 1);
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ gboolean utf8;
+ char *result = my_wnck_get_string_property(wnck_window_get_xid(window), my_wnck_atom_get(value), &utf8);
+
+ if (report & 1) {
+ lua_pushstring(lua, result ? result : "");
+ ret++;
+ }
+ if (report & 2) {
+ lua_pushboolean(lua, utf8);
+ ret++;
+ }
+ g_free (result);
+ } else {
+ //lua_pushstring(lua, "NO RESULT");
+ lua_pushnil(lua);
+ ret++;
+ }
+
+ return ret;
+}
+
+int c_get_window_property(lua_State *lua)
+{
+ return c_get_window_property_internal(lua, "get_window_property", 1);
+}
+
+int c_window_property_is_utf8(lua_State *lua)
+{
+ return c_get_window_property_internal(lua, "window_property_is_utf8", 2);
+}
+
+int c_get_window_property_full(lua_State *lua)
+{
+ return c_get_window_property_internal(lua, "get_window_property_full", 3);
+}
+
+
+/**
+ *
+ */
+int c_set_window_property(lua_State *lua)
+{
+ if (!check_param_counts(lua, "set_window_property", 2, 3)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+ WnckWindow *window = get_current_window();
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TSTRING) {
+ luaL_error(lua, "set_window_property: %s", string_expected_as_indata_error);
+ return 0;
+ }
+
+ const gchar *property = lua_tostring(lua, 1);
+
+ type = lua_type(lua, 2);
+
+ switch (type) {
+ case LUA_TSTRING:
+ gboolean use_utf8 = default_use_utf8;
+ if (top > 2) {
+ type = lua_type(lua, 3);
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_window_property: %s", boolean_expected_as_indata_error);
+ return 0;
+ }
+ use_utf8 = lua_toboolean(lua, 3);
+ }
+ if (!devilspie2_emulate && window)
+ my_wnck_set_string_property(wnck_window_get_xid(window), my_wnck_atom_get(property),
+ lua_tostring(lua, 2), use_utf8);
+ break;
+
+ case LUA_TNUMBER:
+ if (!devilspie2_emulate && window)
+ my_wnck_set_cardinal_property(wnck_window_get_xid(window), my_wnck_atom_get(property),
+ (int32_t) lua_tonumber(lua, 2));
+ break;
+
+ case LUA_TBOOLEAN:
+ if (!devilspie2_emulate && window)
+ my_wnck_set_cardinal_property(wnck_window_get_xid(window), my_wnck_atom_get(property),
+ (int32_t) lua_toboolean(lua, 2));
+ break;
+
+ default:
+ luaL_error(lua, "set_window_property: %s", number_or_string_or_boolean_expected_as_indata_error);
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_delete_window_property(lua_State *lua)
+{
+ if (!check_param_count(lua, "delete_window_property", 1)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TSTRING) {
+ luaL_error(lua, "del_window_property: %s", string_expected_as_indata_error);
+ return 0;
+ }
+
+ const gchar *property = lua_tostring(lua, 1);
+
+ if (!devilspie2_emulate)
+ my_wnck_delete_property(wnck_window_get_xid(window), my_wnck_atom_get(property));
+
+ return 0;
+}
+/**
+ *
+ */
+int c_get_window_role(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_role", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ char *result = my_wnck_get_string_property(wnck_window_get_xid(window), my_wnck_atom_get("WM_WINDOW_ROLE"), NULL);
+
+ lua_pushstring(lua, result ? result : "");
+ g_free (result);
+ } else {
+ lua_pushstring(lua, "");
+ }
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_get_window_xid(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_xid", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ gulong result = window ? wnck_window_get_xid(window) : 0;
+
+ lua_pushinteger(lua, result);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_get_window_class(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_class", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ const char *result = "";
+
+ if (window) {
+ WnckClassGroup *class_group = wnck_window_get_class_group(window);
+ if (class_group) {
+#ifdef WNCK_MAJOR_VERSION
+#if WNCK_CHECK_VERSION(3,2,0)
+ result = (char*)wnck_class_group_get_id(class_group);
+#else
+ result = (char*)wnck_class_group_get_res_class (class_group);
+#endif
+#else
+ result = (char*)wnck_class_group_get_res_class (class_group);
+#endif
+ }
+ }
+
+ lua_pushstring(lua, result);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_set_window_fullscreen(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_window_fullscreen", 1)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ int type = lua_type(lua, 1);
+
+ if (type != LUA_TBOOLEAN) {
+ luaL_error(lua, "set_window_fullscreen: %s",
+ boolean_expected_as_indata_error);
+ return 0;
+ }
+
+ gboolean fullscreen = lua_toboolean(lua, 1);
+
+ if (!devilspie2_emulate && window) {
+ wnck_window_set_fullscreen(window, fullscreen);
+ }
+
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_set_viewport(lua_State *lua)
+{
+ if (!check_param_counts(lua, "set_viewport", 1, 2)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+ int width, height;
+ int viewport_start_x, viewport_start_y;
+ int win_x, win_y;
+ gulong xid;
+ WnckWindow *window;
+
+ switch (top)
+ {
+ case 1:
+ WnckScreen *screen;
+ int x;
+ int type = lua_type(lua, 1);
+ if (type != LUA_TNUMBER) {
+ luaL_error(lua, "set_viewport: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ int num = lua_tonumber(lua,1);
+
+ if (num <= 0) {
+ g_error("set_viewport: %s", integer_greater_than_zero_expected_error);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ window = get_current_window();
+
+ if (!window) {
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ screen = wnck_window_get_screen(window);
+
+ wnck_window_get_geometry(window, &win_x, &win_y, &width, &height);
+
+ xid = wnck_window_get_xid(window);
+
+ //viewport_start = devilspie2_get_viewport_start(xid);
+ if (devilspie2_get_viewport_start(xid, &viewport_start_x, &viewport_start_y) != 0) {
+ g_printerr("set_viewport: %s", could_not_find_current_viewport_error);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ x = ((num - 1) * wnck_screen_get_width(screen)) - viewport_start_x + win_x;
+
+ if (!devilspie2_emulate) {
+ devilspie2_error_trap_push();
+ XMoveResizeWindow(gdk_x11_get_default_xdisplay(),
+ wnck_window_get_xid(window),
+ x, win_y, width, height);
+
+ if (devilspie2_error_trap_pop()) {
+ g_printerr("set_viewport: %s", setting_viewport_failed_error);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+ }
+
+ lua_pushboolean(lua, TRUE);
+ return 1;
+ case 2:
+ int type1 = lua_type(lua, 1);
+ int type2 = lua_type(lua, 2);
+
+ if (type1 != LUA_TNUMBER) {
+ luaL_error(lua, "set_viewport: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ if (type2 != LUA_TNUMBER) {
+ luaL_error(lua, "set_viewport: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ int new_xpos = lua_tonumber(lua, 1);
+ int new_ypos = lua_tonumber(lua, 2);
+
+ window = get_current_window();
+
+ if (!window) {
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ wnck_window_get_geometry(window, &win_x, &win_y, &width, &height);
+
+ xid = wnck_window_get_xid(window);
+
+ //viewport_start = devilspie2_get_viewport_start(xid);
+ if (devilspie2_get_viewport_start(xid, &viewport_start_x, &viewport_start_y) != 0) {
+ g_printerr("set_viewport: %s", could_not_find_current_viewport_error);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ if (!devilspie2_emulate) {
+ devilspie2_error_trap_push();
+ XMoveResizeWindow(gdk_x11_get_default_xdisplay(),
+ wnck_window_get_xid(window),
+ new_xpos, new_ypos, width, height);
+
+ if (devilspie2_error_trap_pop()) {
+ g_printerr("set_viewport: %s", setting_viewport_failed_error);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+ }
+
+ lua_pushboolean(lua, TRUE);
+ return 1;
+ }
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_center(lua_State *lua)
+{
+ if (!check_param_counts_range(lua, "center", 0, 2)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+
+ GdkRectangle desktop_r, window_r;
+
+ WnckWindow *window = get_current_window();
+
+ if (!window) {
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ wnck_window_get_geometry(window, &window_r.x, &window_r.y, &window_r.width, &window_r.height);
+
+ int monitor_no = MONITOR_ALL;
+ enum { CENTRE_NONE, CENTRE_H, CENTRE_V, CENTRE_HV } centre = CENTRE_HV;
+
+ for (int i = 1; i <= top; ++i) {
+ int type = lua_type(lua, i);
+ gchar *indata;
+
+ switch (type) {
+ case LUA_TNUMBER:
+ monitor_no = lua_tonumber(lua, i) - 1;
+ if (monitor_no < MONITOR_ALL || monitor_no >= get_monitor_count())
+ monitor_no = MONITOR_WINDOW; // FIXME: primary monitor; show warning?
+ break;
+ case LUA_TSTRING:
+ indata = (gchar*)lua_tostring(lua, i);
+ switch (*indata & 0xDF) {
+ case 'H':
+ centre = CENTRE_H;
+ break;
+ case 'V':
+ centre = CENTRE_V;
+ break;
+ default:
+ centre = CENTRE_HV;
+ }
+ break;
+ default:
+ luaL_error(lua, "center: %s", number_or_string_expected_as_indata_error);
+ }
+ }
+
+ monitor_no = get_monitor_or_workspace_geometry(monitor_no, window, &desktop_r);
+ if (monitor_no == MONITOR_NONE) {
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+
+ if (centre & 1)
+ window_r.x = desktop_r.x + (desktop_r.width - window_r.width) / 2;
+ else if (window_r.x < desktop_r.x)
+ window_r.x = desktop_r.x;
+ else if (window_r.x + window_r.width >= desktop_r.x + desktop_r.width)
+ window_r.x = desktop_r.x + desktop_r.width - window_r.width;
+
+ if (centre & 2)
+ window_r.y = desktop_r.y + (desktop_r.height - window_r.height) / 2;
+ else if (window_r.y < desktop_r.y)
+ window_r.y = desktop_r.y;
+ else if (window_r.y + window_r.height >= desktop_r.y + desktop_r.height)
+ window_r.y = desktop_r.y + desktop_r.height - window_r.height;
+
+ if (!devilspie2_emulate) {
+ devilspie2_error_trap_push();
+ XMoveWindow (gdk_x11_get_default_xdisplay(),
+ wnck_window_get_xid(window),
+ window_r.x, window_r.y);
+
+ if (devilspie2_error_trap_pop()) {
+ g_printerr("center: %s", failed_string);
+ lua_pushboolean(lua, FALSE);
+ return 1;
+ }
+ }
+
+ lua_pushboolean(lua, TRUE);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_set_window_opacity(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_window_opacity", 1)) {
+ return 0;
+ }
+
+
+ //WnckScreen *screen;
+
+ int type = lua_type(lua, 1);
+ if (type != LUA_TNUMBER) {
+ luaL_error(lua, "set_opacity: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ double value = (double)lua_tonumber(lua, 1);
+ WnckWindow *window = get_current_window();
+
+ if (!devilspie2_emulate && window) {
+ gulong xid = wnck_window_get_xid(window);
+ my_window_set_opacity(xid, value);
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_set_window_type(lua_State *lua)
+{
+ if (!check_param_count(lua, "set_window_type", 1)) {
+ return 0;
+ }
+
+ int type = lua_type(lua, 1);
+ if (type != LUA_TSTRING) {
+ luaL_error(lua, "set_window_type: %s", string_expected_as_indata_error);
+ return 0;
+ }
+
+ gchar *indata = (gchar*)lua_tostring(lua, 1);
+
+ WnckWindow *window = get_current_window();
+
+ if (!devilspie2_emulate && window) {
+ gulong xid = wnck_window_get_xid(window);
+ my_window_set_window_type(xid, indata);
+ }
+
+ return 0;
+}
+
+
+/**
+ * return the geometry of the screen to the Lua script
+ */
+int c_get_screen_geometry(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_screen_geometry", 0)) {
+ return 0;
+ }
+
+ int width = -1, height = -1;
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ WnckScreen *screen;
+ screen = wnck_window_get_screen(window);
+ width = wnck_screen_get_width(screen);
+ height = wnck_screen_get_height(screen);
+ }
+
+ lua_pushinteger(lua, width);
+ lua_pushinteger(lua, height);
+
+ return 2;
+}
+
+
+/**
+ *
+ */
+int c_focus(lua_State *lua)
+{
+ if (!check_param_count(lua, "focus", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (!devilspie2_emulate && window) {
+ wnck_window_activate(window, current_time());
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_close_window(lua_State *lua)
+{
+ if (!check_param_count(lua, "close_window", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (!devilspie2_emulate && window) {
+ wnck_window_close(window, current_time());
+ }
+
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_get_window_fullscreen(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_window_fullscreen", 0)) {
+ return 0;
+ }
+
+ gboolean result = FALSE;
+
+ WnckWindow *window = get_current_window();
+ if (window) {
+ result = wnck_window_is_fullscreen(window);
+ }
+
+ lua_pushboolean(lua, result);
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_get_monitor_index(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_monitor_index", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+ if (window) {
+ int index = get_monitor_index_geometry(window, NULL, NULL);
+ if (index < 0)
+ index = -1; // invalid? assume single monitor
+ lua_pushinteger(lua, index + 1);
+ }
+
+ return 1;
+}
+
+
+/**
+ *
+ */
+int c_get_monitor_geometry(lua_State *lua)
+{
+ if (!check_param_counts(lua, "get_monitor_geometry", 0, 1)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+
+ GdkRectangle geom;
+
+ if (top == 0) {
+ WnckWindow *window = get_current_window();
+ if (!window)
+ return 1; // =nil
+
+ get_monitor_index_geometry(window, NULL, &geom);
+
+ } else if (top == 1) {
+ int type = lua_type(lua, 1);
+
+ if (type!=LUA_TNUMBER) {
+ luaL_error(lua, "get_monitor_geometry: %s",
+ number_expected_as_indata_error);
+ return 0;
+ }
+
+ int index = lua_tonumber(lua, 1) - 1;
+ int actual = get_monitor_geometry(index, &geom);
+
+ if (actual != index)
+ return 0;
+ }
+
+ lua_pushinteger(lua, geom.x);
+ lua_pushinteger(lua, geom.y);
+ lua_pushinteger(lua, geom.width);
+ lua_pushinteger(lua, geom.height);
+
+ return 4;
+}
+
+
+/**
+ *
+ */
+int c_xy(lua_State *lua)
+{
+ if (!check_param_counts(lua, "xy", 0, 2)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+
+ switch (top)
+ {
+ case 0:
+ // return the xy coordinates of the window
+
+ WnckWindow *window = get_current_window();
+ if (window) {
+
+ int x, y, width, height;
+
+ wnck_window_get_geometry(window, &x, &y, &width, &height);
+
+ lua_pushinteger(lua, x);
+ lua_pushinteger(lua, y);
+
+ return 2;
+ }
+ break;
+ case 2:
+ // set the coordinates of the window
+
+ int type1 = lua_type(lua, 1);
+ int type2 = lua_type(lua, 2);
+
+ if ((type1 != LUA_TNUMBER) ||
+ (type2 != LUA_TNUMBER)) {
+ luaL_error(lua, "xy: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ int x = lua_tonumber(lua, 1);
+ int y = lua_tonumber(lua, 2);
+
+ if (!devilspie2_emulate) {
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ if (adjusting_for_decoration)
+ adjust_for_decoration (window, &x, &y, NULL, NULL);
+ wnck_window_set_geometry(window,
+ WNCK_WINDOW_GRAVITY_CURRENT,
+ WNCK_WINDOW_CHANGE_X + WNCK_WINDOW_CHANGE_Y,
+ x, y, -1, -1);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ *
+ */
+int c_xywh(lua_State *lua)
+{
+ if (!check_param_counts(lua, "xywh", 0, 4)) {
+ return 0;
+ }
+
+ int top = lua_gettop(lua);
+
+ switch (top)
+ {
+ case 0:
+ // Return the xywh settings of the window
+
+ WnckWindow *window = get_current_window();
+ if (window) {
+
+ int x, y, width, height;
+
+ wnck_window_get_geometry(window, &x, &y, &width, &height);
+
+ lua_pushinteger(lua, x);
+ lua_pushinteger(lua, y);
+ lua_pushinteger(lua, width);
+ lua_pushinteger(lua, height);
+
+ return 4;
+ }
+ break;
+ case 4:
+ // Set the xywh settings in the window
+
+
+ int type1 = lua_type(lua, 1);
+ int type2 = lua_type(lua, 2);
+ int type3 = lua_type(lua, 3);
+ int type4 = lua_type(lua, 4);
+
+ if ((type1 != LUA_TNUMBER) ||
+ (type2 != LUA_TNUMBER) ||
+ (type3 != LUA_TNUMBER) ||
+ (type4 != LUA_TNUMBER)) {
+ luaL_error(lua, "xywh: %s", number_expected_as_indata_error);
+ return 0;
+ }
+
+ int x = lua_tonumber(lua, 1);
+ int y = lua_tonumber(lua, 2);
+ int xsize = lua_tonumber(lua, 3);
+ int ysize = lua_tonumber(lua, 4);
+
+ if (!devilspie2_emulate) {
+ WnckWindow *window = get_current_window();
+ if (window) {
+ set_window_geometry(window, x, y, xsize, ysize, adjusting_for_decoration);
+ }
+ }
+
+ return 0;
+ }
+ return 0;
+}
+
+struct lua_callback {
+ lua_State *lua;
+ int ref;
+};
+
+static void on_geometry_changed(WnckWindow *window, struct lua_callback *callback)
+{
+ if (callback == NULL)
+ return;
+
+ WnckWindow *old_window = get_current_window();
+ set_current_window(window);
+
+ lua_rawgeti(callback->lua, LUA_REGISTRYINDEX, callback->ref);
+ lua_pcall(callback->lua, 0, 0, 0);
+
+ set_current_window(old_window);
+}
+
+static void on_geometry_changed_disconnect(gpointer data, GClosure *closure G_GNUC_UNUSED)
+{
+ g_free(data);
+}
+
+/**
+ *
+ */
+int c_on_geometry_changed(lua_State *lua)
+{
+ if (!check_param_count(lua, "on_geometry_changed", 1)) {
+ return 0;
+ }
+
+ if (lua_type(lua, 1) != LUA_TFUNCTION) {
+ luaL_error(lua, "on_geometry_changed: %s", "function expected");
+ return 0;
+ }
+
+ struct lua_callback *cb = g_malloc(sizeof(struct lua_callback));
+ cb->lua = lua;
+ cb->ref = luaL_ref(lua, LUA_REGISTRYINDEX);
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ g_signal_connect_data(window, "geometry-changed", G_CALLBACK(on_geometry_changed), (gpointer)cb, (GClosureNotify)(on_geometry_changed_disconnect), 0);
+ }
+
+ return 0;
+}
+
+/**
+ * returns the process binary name
+ */
+static ATTR_MALLOC gchar *c_get_process_name_INT_proc(lua_State *, pid_t);
+static ATTR_MALLOC gchar *c_get_process_name_INT_ps(lua_State *, pid_t);
+
+int c_get_process_name(lua_State *lua)
+{
+ if (!check_param_count(lua, "get_process_name", 0)) {
+ return 0;
+ }
+
+ WnckWindow *window = get_current_window();
+
+ if (window) {
+ pid_t pid = wnck_window_get_pid(window);
+
+ if (pid != 0) {
+ gchar *cmdname = c_get_process_name_INT_proc(lua, pid);
+ if (!cmdname)
+ cmdname = c_get_process_name_INT_ps(lua, pid);
+
+ /* chop off any trailing LF */
+ gchar *lf = cmdname + strlen(cmdname) - 1;
+ if (lf >= cmdname && *lf == '\n')
+ *lf = 0;
+
+ lua_pushstring(lua, cmdname ? cmdname : "");
+ g_free(cmdname);
+ return 1;
+ }
+ }
+
+ lua_pushstring(lua, "");
+ return 1;
+}
+
+static gchar *c_get_process_name_INT_proc(lua_State *lua, pid_t pid)
+{
+ /* 16 is fine for cmdname on Linux. Could be longer elsewhere, though. */
+ char cmd[1024], cmdname[1024];
+ FILE *cmdfp;
+
+ cmdname[0] = 0;
+
+ snprintf(cmd, sizeof(cmd), "/proc/%lu/comm", (unsigned long)pid);
+ cmdfp = fopen(cmd, "r");
+ if (cmdfp == NULL) {
+ if (errno != ENOENT && errno != EACCES) {
+ luaL_error(lua, "get_process_name: Failed to open \"%s\" (%d).", cmd, errno);
+ }
+ return NULL;
+ }
+
+ if (fgets(cmdname, sizeof(cmdname), cmdfp) == NULL) {
+ fclose(cmdfp);
+ luaL_error(lua, "get_process_name: Failed to read from \"%s\".", cmd);
+ return NULL;
+ }
+
+ fclose(cmdfp);
+ return g_strdup(cmdname);
+}
+
+static gchar *c_get_process_name_INT_ps(lua_State *lua, pid_t pid)
+{
+ char cmd[1024], cmdname[1024];
+ FILE *cmdfp;
+
+ /* I'd like to use "ps ho comm c %lu" here.
+ * Seems that FreeBSD ps outputs headers regardless.
+ * (Tested using procps 'ps' with PS_PERSONALITY=bsd)
+ */
+ snprintf(cmd, sizeof(cmd), "ps o comm c %lu | tail -n 1", (unsigned long)pid);
+ cmdfp = popen(cmd, "r");
+ if (cmdfp == NULL) {
+ luaL_error(lua, "get_process_name: Failed to run command \"%s\".", cmd);
+ return 0;
+ }
+
+ if (fgets(cmdname, sizeof(cmdname), cmdfp) == NULL) {
+ pclose(cmdfp);
+ luaL_error(lua, "get_process_name: Failed to read output from command \"%s\".", cmd);
+ return 0;
+ }
+
+ pclose(cmdfp);
+ return g_strdup(cmdname);
+}
+
+
+/**
+ *
+ */
+int c_millisleep(lua_State *lua)
+{
+ if (!check_param_count(lua, "millisleep", 1)) {
+ return 0;
+ }
+ if (lua_type(lua, 1) != LUA_TNUMBER) {
+ luaL_error(lua, "millisleep: %s",
+ number_expected_as_indata_error);
+ return 0;
+ }
+
+ int time = lua_tonumber(lua, 1);
+ if (time < 1 || time > 1000) {
+ luaL_error(lua, _("millisleep: time %d out of range (1..1000)"), time);
+ return 0;
+ }
+
+ struct timespec tv;
+ struct timespec left;
+ if (time == 1000) {
+ tv.tv_sec = 1;
+ tv.tv_nsec = 0;
+ } else {
+ tv.tv_sec = 0;
+ tv.tv_nsec = time * 1000000;
+ }
+ while (nanosleep(&tv, &left) && errno == EINTR)
+ tv = left;
+
+ return 0;
+}
+
+
+/*
+ * Devilspie:
+
+ * Focus the current window.
+
+ESExpResult *func_focus(ESExp *f, int argc, ESExpResult **argv, Context *c) {
+ wnck_window_activate (c->window, current_time());
+ if (debug) g_printerr (_("Focusing\n"));
+ return e_sexp_result_new_bool (f, TRUE);
+}
+
+*/