/** * 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 . */ #include "glib.h" #include #include #include #include #define WNCK_I_KNOW_THIS_IS_UNSTABLE #include #include #include #include #include #include #include #include "intl.h" #include #include #include #include #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); } */