diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Makefile.am | 1 | ||||
| -rw-r--r-- | tools/slit/Makefile.am | 17 | ||||
| -rw-r--r-- | tools/slit/slit.c | 634 |
3 files changed, 652 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..a66187c7 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = slit diff --git a/tools/slit/Makefile.am b/tools/slit/Makefile.am new file mode 100644 index 00000000..b9aa5058 --- /dev/null +++ b/tools/slit/Makefile.am @@ -0,0 +1,17 @@ +rcdir=$(datadir)/openbox + +INCLUDES=-I../.. + +CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \ + -DRCDIR=\"$(rcdir)\" \ + -DG_LOG_DOMAIN=\"ObSlit\" +LIBS=$(X_LIBS) $(XFT_LIBS) $(GLIB_LIBS) @LIBS@ @LIBINTL@ + +bin_PROGRAMS=obslit + +obslit_LDADD=-lobrender -L../../render +obslit_SOURCES=slit.c +MAINTAINERCLEANFILES=Makefile.in + +distclean-local: + $(RM) *\~ *.orig *.rej .\#* diff --git a/tools/slit/slit.c b/tools/slit/slit.c new file mode 100644 index 00000000..28d9303e --- /dev/null +++ b/tools/slit/slit.c @@ -0,0 +1,634 @@ +#include "render/render.h" +#include "render/theme.h" + +#include <X11/Xlib.h> +#include <stdlib.h> +#include <glib.h> +#ifdef HAVE_SIGNAL_H +# include <signal.h> +#endif +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif + +#define TITLE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \ + ButtonMotionMask) +#define ROOT_EVENT_MASK (PropertyChangeMask | StructureNotifyMask | \ + SubstructureNotifyMask) +#define SLITAPP_EVENT_MASK (StructureNotifyMask) + +Display *ob_display; +Window ob_root; +int ob_screen; + +static struct Slit { + Window frame; + Window title; + + /* user-requested position stuff */ + int gravity; + int user_x, user_y; + + /* actual position (when not auto-hidden) */ + int x, y; + int w, h; + + gboolean horz; + + Appearance *a_frame; + Appearance *a_title; + + GList *slit_apps; +} *slit; +static int nslits; + +struct SlitApp { + Window icon_win; + Window win; + int x; + int y; + int w; + int h; +}; + +static Atom atom_atom; +static Atom atom_card; +static Atom atom_theme; +static Atom atom_type; +static Atom atom_type_dock; +static Atom atom_desktop; +static Atom atom_state; +static Atom atom_strut; + +static gboolean quit = FALSE; +static gboolean reconfig = FALSE; + +void slit_read_theme(); +void slit_configure(); +void event_handle(XEvent *e); +void slit_add_existing(); +void slit_add_app(Window win); +void slit_remove_app(struct Slit *slit, struct SlitApp *app,gboolean reparent); + +void sighandler(int signal) +{ + if (signal == SIGUSR1) + reconfig =TRUE; + else + quit = TRUE; +} + +int xerrorhandler(Display *d, XErrorEvent *e) +{ + char errtxt[128]; + XGetErrorText(d, e->error_code, errtxt, 127); + g_error("X Error: %s", errtxt); + return 0; +} + +int main() +{ + int i; + guint desk = 0xffffffff; + XEvent e; + XSetWindowAttributes attrib; + struct sigaction action; + sigset_t sigset; + int xfd; + fd_set selset; + + /* set up signal handler */ + sigemptyset(&sigset); + action.sa_handler = sighandler; + action.sa_mask = sigset; + action.sa_flags = SA_NOCLDSTOP; + sigaction(SIGUSR1, &action, (struct sigaction *) NULL); + sigaction(SIGPIPE, &action, (struct sigaction *) NULL); + sigaction(SIGSEGV, &action, (struct sigaction *) NULL); + sigaction(SIGFPE, &action, (struct sigaction *) NULL); + sigaction(SIGTERM, &action, (struct sigaction *) NULL); + sigaction(SIGINT, &action, (struct sigaction *) NULL); + sigaction(SIGHUP, &action, (struct sigaction *) NULL); + + ob_display = XOpenDisplay(NULL); + ob_screen = DefaultScreen(ob_display); + ob_root = RootWindow(ob_display, ob_screen); + + XSetErrorHandler(xerrorhandler); + + render_startup(); + theme_startup(); + + atom_atom = XInternAtom(ob_display, "ATOM", False); + atom_card = XInternAtom(ob_display, "CARDINAL", False); + atom_theme = XInternAtom(ob_display, "_OPENBOX_THEME", False); + atom_type = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE", False); + atom_type_dock = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE_DOCK",False); + atom_desktop =XInternAtom(ob_display, "_NET_WM_DESKTOP", False); + atom_state = XInternAtom(ob_display, "WM_STATE", False); + atom_strut = XInternAtom(ob_display, "_NET_WM_STRUT", False); + + nslits = 1; + slit = g_new0(struct Slit, nslits); + + for (i = 0; i < nslits; ++i) { + slit[i].horz = TRUE; + + slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0, + render_depth, InputOutput, render_visual, + 0, NULL); + attrib.event_mask = TITLE_EVENT_MASK; + slit[i].title = XCreateWindow(ob_display, slit[i].frame, 0, 0, 1, 1, 0, + render_depth, InputOutput, render_visual, + CWEventMask, &attrib); + XMapWindow(ob_display, slit[i].title); + + XChangeProperty(ob_display, slit[i].frame, atom_type, atom_atom, + 32, PropModeReplace, (guchar*)&atom_type_dock, 1); + + XChangeProperty(ob_display, slit[i].frame, atom_desktop, atom_card, + 32, PropModeReplace, (guchar*)&desk, 1); + } + + slit_read_theme(); + + XSelectInput(ob_display, ob_root, ROOT_EVENT_MASK); + + slit_add_existing(); + + xfd = ConnectionNumber(ob_display); + FD_ZERO(&selset); + FD_SET(xfd, &selset); + while (!quit) { + gboolean hadevent = FALSE; + while (XPending(ob_display)) { + XNextEvent(ob_display, &e); + event_handle(&e); + hadevent = TRUE; + } + if (!hadevent) { + if (reconfig) + slit_read_theme(); + + if (!quit) + select(xfd + 1, &selset, NULL, NULL, NULL); + } + } + + for (i = 0; i < nslits; ++i) { + while (slit[i].slit_apps) + slit_remove_app(&slit[i], slit[i].slit_apps->data, TRUE); + + XDestroyWindow(ob_display, slit[i].title); + XDestroyWindow(ob_display, slit[i].frame); + + appearance_free(slit[i].a_frame); + appearance_free(slit[i].a_title); + } + + theme_shutdown(); + render_shutdown(); + XCloseDisplay(ob_display); + return 0; +} + +Window find_client(Window win) +{ + Window r, *children; + unsigned int n, i; + Atom ret_type; + int ret_format; + unsigned long ret_items, ret_bytesleft; + unsigned long *prop_return; + + XQueryTree(ob_display, win, &r, &r, &children, &n); + for (i = 0; i < n; ++i) { + Window w = find_client(children[i]); + if (w) return w; + } + + /* try me */ + XGetWindowProperty(ob_display, win, atom_state, 0, 1, + False, atom_state, &ret_type, &ret_format, + &ret_items, &ret_bytesleft, + (unsigned char**) &prop_return); + if (ret_type == None || ret_items < 1) + return None; + return win; /* found it! */ +} + +void event_handle(XEvent *e) +{ + int i; + Window win; + static guint button = 0; + int sw, sh; + int xpos, ypos; + int x, y, g; + + switch (e->type) { + case ButtonPress: + if (!button) { + button = e->xbutton.button; + } + break; + case ButtonRelease: + if (button == e->xbutton.button) + button = 0; + break; + case MotionNotify: + if (button == 1) { + for (i = 0; i < nslits; ++i) + if (slit[i].title == e->xmotion.window) { + /* pick a corner and move it */ + sw = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + sh = HeightOfScreen(ScreenOfDisplay(ob_display,ob_screen)); + + if (e->xmotion.x_root < sw / 3) /* left edge */ + xpos = 0; + else if (e->xmotion.x_root < sw / 3 * 2) /* middle */ + xpos = 1; + else /* right edge */ + xpos = 2; + if (e->xmotion.y_root < sh / 3) /* top edge */ + ypos = 0; + else if (e->xmotion.y_root < sh / 3 * 2) /* middle */ + ypos = 1; + else /* bottom edge */ + ypos = 2; + + if (xpos == 1 && ypos == 1) + return; /* cant go in middle middle */ + + if (xpos == 0) { + if (ypos == 0) { + x = 0; + y = 0; + g = NorthWestGravity; + } else if (ypos == 1) { + x = 0; + y = sh / 2; + g = WestGravity; + } else { + x = 0; + y = sh; + g = SouthWestGravity; + } + } else if (xpos == 1) { + if (ypos == 0) { + x = sw / 2; + y = 0; + g = NorthGravity; + } else { + x = sw / 2; + y = sh; + g = SouthGravity; + } + } else { + if (ypos == 0) { + x = sw; + y = 0; + g = NorthEastGravity; + } else if (ypos == 1) { + x = sw; + y = sh / 2; + g = EastGravity; + } else { + x = sw; + y = sh; + g = SouthEastGravity; + } + } + if (x != slit[i].x || y != slit[i].y || + g != slit[i].gravity) { + slit[i].user_x = x; + slit[i].user_y = y; + slit[i].gravity = g; + slit_configure(); + } + } + } + break; + case PropertyNotify: + g_message("PropertyNotify on 0x%lx", e->xproperty.window); + if (e->xproperty.window == ob_root) { + if (e->xproperty.atom == atom_theme) + slit_read_theme(); + } + break; + case ConfigureNotify: + g_message("ConfigureNotify on 0x%lx", e->xconfigure.window); + if (e->xconfigure.window == ob_root) { + slit_configure(); + return; + } + + /* an owned slitapp? */ + for (i = 0; i < nslits; ++i) { + GList *it; + + for (it = slit[i].slit_apps; it; it = it->next) { + struct SlitApp *app = it->data; + if (e->xconfigure.window == app->icon_win) { + if (app->w != e->xconfigure.width || + app->h != e->xconfigure.height) { + g_message("w %d h %d w %d h %d", + app->w, e->xconfigure.width, + app->h, e->xconfigure.height); + app->w = e->xconfigure.width; + app->h = e->xconfigure.height; + slit_configure(); + } + return; + } + } + } + break; + case MapNotify: + g_message("MapNotify on 0x%lx", e->xmap.window); + + win = find_client(e->xmap.window); + if (!win) return; + + for (i = 0; i < nslits; ++i) + if (win == slit[i].frame) + return; + + slit_add_app(win); + break; + case UnmapNotify: + g_message("UnmapNotify on 0x%lx", e->xunmap.window); + for (i = 0; i < nslits; ++i) { + GList *it; + + for (it = slit[i].slit_apps; it; it = it->next) { + struct SlitApp *app = it->data; + if (e->xunmap.window == app->icon_win) { + gboolean r; + XEvent e; + + r = !XCheckTypedWindowEvent(ob_display, app->icon_win, + DestroyNotify, &e); + if (r) { + if (XCheckTypedWindowEvent(ob_display, app->icon_win, + ReparentNotify, &e)) { + XPutBackEvent(ob_display, &e); + r = FALSE; + } + } + slit_remove_app(&slit[i], app, r); + break; + } + } + } + break; + case ReparentNotify: + g_message("ReparentNotify on 0x%lx", e->xdestroywindow.window); + for (i = 0; i < nslits; ++i) { + GList *it; + + for (it = slit[i].slit_apps; it; it = it->next) { + struct SlitApp *app = it->data; + if (e->xdestroywindow.window == app->icon_win) { + slit_remove_app(&slit[i], app, FALSE); + break; + } + } + } + case DestroyNotify: + g_message("DestroyNotify on 0x%lx", e->xdestroywindow.window); + for (i = 0; i < nslits; ++i) { + GList *it; + + for (it = slit[i].slit_apps; it; it = it->next) { + struct SlitApp *app = it->data; + if (e->xdestroywindow.window == app->icon_win) { + slit_remove_app(&slit[i], app, FALSE); + break; + } + } + } + break; + } +} + +void slit_add_existing() +{ + unsigned int i, nchild; + int j; + Window w, *children; + XWindowAttributes attrib; + + XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild); + + for (i = 0; i < nchild; ++i) { + for (j = 0; j < nslits; ++j) + if (children[i] == slit[j].frame) + continue; + if (children[i] == None) + continue; + if ((children[i] = find_client(children[i])) == None) + continue; + if (XGetWindowAttributes(ob_display, children[i], &attrib)) { + if (attrib.override_redirect) continue; + + slit_add_app(children[i]); + } + } + XFree(children); +} + +void slit_add_app(Window win) +{ + int i; + XWMHints *h; + XWindowAttributes attrib; + struct Slit *s; + + s = &slit[0]; + + if ((h = XGetWMHints(ob_display, win))) { + if (h->flags & StateHint && h->initial_state == WithdrawnState) { + struct SlitApp *app = g_new(struct SlitApp, 1); + + app->win = win; + app->icon_win = (h->flags & IconWindowHint) ? + h->icon_window : win; + + XFree(h); + + for (i = 0; i < nslits; ++i) { + GList *it; + for (it = slit[i].slit_apps; it; it = it->next) + if (app->icon_win == + ((struct SlitApp*)it->data)->icon_win) + /* already managed! */ + return; + } + + if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) { + app->w = attrib.width; + app->h = attrib.height; + } else { + g_free(app); + app = NULL; + } + + if (app) { + s->slit_apps = g_list_append(s->slit_apps, app); + slit_configure(); + XReparentWindow(ob_display, app->icon_win, + s->frame, app->x, app->y); +/* if (app->win != app->icon_win) + XUnmapWindow(ob_display, app->win);*/ + XSync(ob_display, False); + XSelectInput(ob_display, app->icon_win, + SLITAPP_EVENT_MASK); + } + g_message("Managed: 0x%lx", app->icon_win); + } else + XFree(h); + } +} + +void slit_remove_app(struct Slit *slit, struct SlitApp *app, gboolean reparent) +{ + + XSelectInput(ob_display, app->icon_win, NoEventMask); + XSync(ob_display, False); + if (reparent) { + g_message("reparenting"); +/* if (app->win != app->icon_win) + XMapWindow(ob_display, app->win);*/ + XReparentWindow(ob_display, app->icon_win, ob_root, 0, 0); + } + + g_free(app); + slit->slit_apps = g_list_remove(slit->slit_apps, app); + slit_configure(); +} + +void slit_read_theme() +{ + XTextProperty prop; + int i; + char *theme = NULL; + + if (XGetTextProperty(ob_display, ob_root, &prop, + XInternAtom(ob_display, "_OPENBOX_THEME", False))) { + theme = theme_load((char*)prop.value); + XFree(prop.value); + } else + theme = theme_load(NULL); + + g_free(theme); + if (!theme) exit(EXIT_FAILURE); + + for (i = 0; i < nslits; ++i) { + appearance_free(slit[i].a_frame); + appearance_free(slit[i].a_title); + + slit[i].a_frame = appearance_copy(theme_a_unfocused_title); + slit[i].a_title = appearance_copy(theme_a_unfocused_title); + + XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel); + XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth); + XSetWindowBorder(ob_display, slit[i].frame, BlackPixel(ob_display, ob_screen)); + XSetWindowBorderWidth(ob_display, slit[i].frame, 30); + } + + slit_configure(); +} + +void slit_configure() +{ + int i; + int titleh; + GList *it; + int spot; + + titleh = 4; + + for (i = 0; i < nslits; ++i) { + if (slit[i].horz) { + slit[i].w = titleh; + slit[i].h = 0; + } else { + slit[i].w = 0; + slit[i].h = titleh; + } + spot = titleh; + + for (it = slit[i].slit_apps; it; it = it->next) { + struct SlitApp *app = it->data; + if (slit[i].horz) { + g_message("%d", spot); + app->x = spot; + app->y = 0; + slit[i].w += app->w; + slit[i].h = MAX(slit[i].h, app->h); + spot += app->w; + } else { + app->x = 0; + app->y = spot; + slit[i].w = MAX(slit[i].h, app->w); + slit[i].h += app->h; + spot += app->h; + } + + XMoveWindow(ob_display, app->icon_win, app->x, app->y); + } + + /* calculate position */ + slit[i].x = slit[i].user_x; + slit[i].y = slit[i].user_y; + + switch(slit[i].gravity) { + case NorthGravity: + case CenterGravity: + case SouthGravity: + slit[i].x -= slit[i].w / 2; + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + slit[i].x -= slit[i].w; + break; + } + switch(slit[i].gravity) { + case WestGravity: + case CenterGravity: + case EastGravity: + slit[i].y -= slit[i].h / 2; + break; + case SouthWestGravity: + case SouthGravity: + case SouthEastGravity: + slit[i].y -= slit[i].h; + break; + } + + if (slit[i].w > 0 && slit[i].h > 0) { + RECT_SET(slit[i].a_frame->area, 0, 0, slit[i].w, slit[i].h); + XMoveResizeWindow(ob_display, slit[i].frame, + slit[i].x - theme_bwidth, + slit[i].y - theme_bwidth, + slit[i].w, slit[i].h); + + if (slit[i].horz) { + RECT_SET(slit[i].a_title->area, 0, 0, titleh, slit[i].h); + XMoveResizeWindow(ob_display, slit[i].title, 0, 0, + titleh, slit[i].h); + } else { + RECT_SET(slit[i].a_title->area, 0, 0, slit[i].w, titleh); + XMoveResizeWindow(ob_display, slit[i].title, 0, 0, + slit[i].w, titleh); + } + + paint(slit[i].frame, slit[i].a_frame); + paint(slit[i].title, slit[i].a_title); + XMapWindow(ob_display, slit[i].frame); + } else + XUnmapWindow(ob_display, slit[i].frame); + } +} |
