[client] Add client_redraw (FS#170)
[awesome.git] / uicb.c
blobcc8bd6883b64296fb60404c4a674d3fa6795d534
1 /*
2 * uicb.c - user interface callbacks management
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 /**
23 * @defgroup ui_callback User Interface Callbacks
26 #include <sys/wait.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
31 #include <xcb/xcb.h>
32 #include <xcb/xcb_aux.h>
34 #include "awesome.h"
35 #include "tag.h"
36 #include "mouse.h"
37 #include "statusbar.h"
38 #include "widget.h"
39 #include "focus.h"
40 #include "client.h"
41 #include "screen.h"
42 #include "titlebar.h"
43 #include "layouts/tile.h"
45 extern AwesomeConf globalconf;
47 const name_func_link_t UicbList[] =
49 /* awesome.h */
50 { "quit", uicb_quit },
51 /* client.h */
52 { "client_kill", uicb_client_kill },
53 { "client_moveresize", uicb_client_moveresize },
54 { "client_settrans", uicb_client_settrans },
55 { "client_swap", uicb_client_swap },
56 { "client_togglemax", uicb_client_togglemax },
57 { "client_focus", uicb_client_focus },
58 { "client_setfloating", uicb_client_setfloating },
59 { "client_togglescratch", uicb_client_togglescratch },
60 { "client_setscratch", uicb_client_setscratch },
61 { "client_redraw", uicb_client_redraw },
62 /* focus.h */
63 { "focus_history", uicb_focus_history },
64 { "focus_client_byname", uicb_focus_client_byname },
65 /* layout.h */
66 { "tag_setlayout", uicb_tag_setlayout },
67 /* mouse.h */
68 { "client_movemouse", uicb_client_movemouse },
69 { "client_resizemouse", uicb_client_resizemouse },
70 /* screen.h */
71 { "screen_focus", uicb_screen_focus },
72 { "client_movetoscreen", uicb_client_movetoscreen },
73 /* statusbar.h */
74 { "statusbar_toggle", uicb_statusbar_toggle },
75 /* tag.h */
76 { "client_tag", uicb_client_tag },
77 { "client_toggletag", uicb_client_toggletag },
78 { "tag_toggleview", uicb_tag_toggleview },
79 { "tag_view", uicb_tag_view },
80 { "tag_prev_selected", uicb_tag_prev_selected },
81 { "tag_viewnext", uicb_tag_viewnext },
82 { "tag_viewprev", uicb_tag_viewprev },
83 { "tag_create", uicb_tag_create },
84 /* titlebar.h */
85 { "client_toggletitlebar", uicb_client_toggletitlebar },
86 /* uicb.h */
87 { "restart", uicb_restart },
88 { "exec", uicb_exec },
89 { "spawn", uicb_spawn },
90 /* widget.h */
91 { "widget_tell", uicb_widget_tell },
92 /* layouts/tile.h */
93 { "tag_setnmaster", uicb_tag_setnmaster},
94 { "tag_setncol", uicb_tag_setncol },
95 { "tag_setmwfact", uicb_tag_setmwfact },
96 { NULL, NULL }
99 /** Restart awesome with the current command line.
100 * \param screen The virtual screen number.
101 * \param arg An unused argument.
102 * \ingroup ui_callback
104 void
105 uicb_restart(int screen, char *arg __attribute__ ((unused)))
107 uicb_exec(screen, globalconf.argv);
110 /** Execute another process, replacing the current instance of awesome.
111 * \param screen The virtual screen number.
112 * \param cmd The command to start.
113 * \ingroup ui_callback
115 void
116 uicb_exec(int screen __attribute__ ((unused)), char *cmd)
118 client_t *c;
119 char *args, *path;
121 /* remap all clients since some WM won't handle them otherwise */
122 for(c = globalconf.clients; c; c = c->next)
123 client_unban(c);
125 xcb_aux_sync(globalconf.connection);
126 xcb_disconnect(globalconf.connection);
128 /* Ignore the leading spaces if any */
129 while(cmd[0] && cmd[0] == ' ')
130 cmd++;
132 /* Get the beginning of the arguments */
133 args = strchr(cmd, ' ');
135 if(args)
136 path = a_strndup(cmd, args - cmd);
137 else
138 path = a_strndup(cmd, a_strlen(cmd));
140 execlp(path, cmd, NULL);
142 p_delete(&path);
145 /** Spawn another process.
146 * \param screen The virtual screen number.
147 * \param arg The command to run.
148 * \ingroup ui_callback
150 void
151 uicb_spawn(int screen, char *arg)
153 static char *shell = NULL;
154 char *display = NULL;
155 char *tmp, newdisplay[128];
157 if(!arg)
158 return;
160 if(!shell && !(shell = getenv("SHELL")))
161 shell = a_strdup("/bin/sh");
163 if(!globalconf.screens_info->xinerama_is_active && (tmp = getenv("DISPLAY")))
165 display = a_strdup(tmp);
166 if((tmp = strrchr(display, '.')))
167 *tmp = '\0';
168 snprintf(newdisplay, sizeof(newdisplay), "%s.%d", display, screen);
169 setenv("DISPLAY", newdisplay, 1);
172 /* The double-fork construct avoids zombie processes and keeps the code
173 * clean from stupid signal handlers. */
174 if(fork() == 0)
176 if(fork() == 0)
178 if(globalconf.connection)
179 close(xcb_get_file_descriptor(globalconf.connection));
180 setsid();
181 execl(shell, shell, "-c", arg, NULL);
182 warn("execl '%s -c %s' failed: %s\n", shell, arg, strerror(errno));
184 exit(EXIT_SUCCESS);
186 wait(0);
189 /** Run the uicb.
190 * \param cmd The uicb command to parse.
191 * \return true on succes, false on failure.
193 static bool
194 __uicb_run(char *cmd)
196 char *p, *argcpy;
197 const char *arg;
198 int screen;
199 ssize_t len;
200 uicb_t *uicb;
202 len = a_strlen(cmd);
203 p = strtok(cmd, " ");
204 if (!p)
206 warn("ignoring malformed command\n");
207 return false;
209 screen = atoi(cmd);
210 if(screen >= globalconf.screens_info->nscreen || screen < 0)
212 warn("invalid screen specified: %i\n", screen);
213 return false;
216 p = strtok(NULL, " ");
217 if (!p)
219 warn("ignoring malformed command.\n");
220 return false;
223 uicb = name_func_lookup(p, UicbList);
224 if (!uicb)
226 warn("unknown uicb function: %s.\n", p);
227 return false;
230 if (p + a_strlen(p) < cmd + len)
232 arg = p + a_strlen(p) + 1;
233 len = a_strlen(arg);
234 /* Allow our callees to modify this string. */
235 argcpy = p_new(char, len + 1);
236 a_strncpy(argcpy, len + 1, arg, len);
237 uicb(screen, argcpy);
238 p_delete(&argcpy);
240 else
241 uicb(screen, NULL);
243 return true;
246 /** Parse a command.
247 * \param cmd The buffer to parse.
248 * \return true on succes, false on failure.
250 bool
251 __uicb_parsecmd(char *cmd)
253 char *p, *curcmd = cmd;
254 bool ret = false;
256 if(a_strlen(cmd))
257 while((p = strchr(curcmd, '\n')))
259 *p = '\0';
260 ret = __uicb_run(curcmd);
261 curcmd = p + 1;
264 return ret;
267 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80