wmfs/src/client.c
2010-04-22 17:56:35 +02:00

1286 lines
29 KiB
C

/*
* client.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/** Attach client in the client chain
* \param c Client pointer
*/
void
client_attach(Client *c)
{
if(clients)
clients->prev = c;
c->next = clients;
clients = c;
return;
}
/** Send a ConfigureRequest event to the Client
* \param c Client pointer
*/
void
client_configure(Client *c)
{
XConfigureEvent ev;
ev.type = ConfigureNotify;
ev.event = c->win;
ev.window = c->win;
ev.x = c->geo.x;
ev.y = c->geo.y;
ev.width = c->geo.width;
ev.height = c->geo.height;
ev.above = None;
ev.border_width = 0;
ev.override_redirect = 0;
XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ev);
return;
}
/** Detach a client to the client chain
* \param c Client pointer
*/
void
client_detach(Client *c)
{
Client **cc;
for(cc = &clients; *cc && *cc != c; cc = &(*cc)->next);
*cc = c->next;
return;
}
/** Get the next client
*\return The next client or NULL
*/
Client*
client_get_next(void)
{
Client *c = NULL;
if(!sel || ishide(sel, selscreen))
return NULL;
for(c = sel->next; c && ishide(c, selscreen); c = c->next);
if(!c && conf.client_round)
for(c = clients; c && ishide(c, selscreen); c = c->next);
return c;
}
/** Get the previous client
*\return The previous client or NULL
*/
Client*
client_get_prev(void)
{
Client *c = NULL, *d;
if(!sel || ishide(sel, selscreen))
return NULL;
for(d = clients; d != sel; d = d->next)
if(!ishide(d, selscreen))
c = d;
if(!c && conf.client_round)
for(; d; d = d->next)
if(!ishide(d, selscreen))
c = d;
return c;
}
/** Switch to the previous client
* \param cmd uicb_t type unused
*/
void
uicb_client_prev(uicb_t cmd)
{
Client *c;
if((c = client_get_prev()))
{
client_focus(c);
client_raise(c);
}
return;
}
/** Switch to the next client
* \param cmd uicb_t type unused
*/
void
uicb_client_next(uicb_t cmd)
{
Client *c;
if((c = client_get_next()))
{
client_focus(c);
client_raise(c);
}
return;
}
/** Swap the current client with the next one
*\param cmd uicb_t type unused
*/
void
uicb_client_swap_next(uicb_t cmd)
{
Client *c;
if((c = client_get_next()))
{
client_swap(sel, c);
client_focus(c);
}
return;
}
/** Swap the current client with the previous one
*\param cmd uicb_t type unused
*/
void
uicb_client_swap_prev(uicb_t cmd)
{
Client *c;
if((c = client_get_prev()))
{
client_swap(sel, c);
client_focus(c);
}
return;
}
/** Set the client c above
*\param c Client pointer
*/
void
client_above(Client *c)
{
XRectangle geo = { 0 };
if(c->flags & AboveFlag)
return;
c->flags |= AboveFlag;
geo.height = spgeo[c->screen].height * 0.75;
geo.width = spgeo[c->screen].width * 0.75;
geo.y = spgeo[c->screen].y + (spgeo[c->screen].height / 2) - (geo.height / 2);
geo.x = spgeo[c->screen].x + (spgeo[c->screen].width / 2)- (geo.width / 2);
client_moveresize(c, geo, tags[c->screen][c->tag].resizehint);
client_raise(c);
tags[c->screen][c->tag].layout.func(c->screen);
return;
}
/** Set the focus to a client
* \param c Client pointer
*/
void
client_focus(Client *c)
{
Window w;
int d;
if(sel && sel != c)
{
sel->colors.frame = conf.client.bordernormal;
sel->colors.fg = conf.titlebar.fg_normal;
sel->colors.resizecorner = conf.client.resizecorner_normal;
if(TBARH - BORDH && sel->titlebar->stipple)
sel->titlebar->stipple_color = conf.titlebar.stipple.colors.normal;
if(sel->flags & AboveFlag)
sel->flags &= ~AboveFlag;
frame_update(sel);
mouse_grabbuttons(sel, !conf.focus_pclick);
}
if((sel = c))
{
c->colors.frame = conf.client.borderfocus;
c->colors.fg = conf.titlebar.fg_focus;
c->colors.resizecorner = conf.client.resizecorner_focus;
if(TBARH - BORDH && c->titlebar->stipple)
c->titlebar->stipple_color = conf.titlebar.stipple.colors.focus;
frame_update(c);
mouse_grabbuttons(c, True);
if(conf.raisefocus)
{
XQueryPointer(dpy, ROOT, &w, &w, &d, &d, &d, &d, (uint *)&d);
if(c == client_gb_win(w)
|| c == client_gb_frame(w)
|| c == client_gb_titlebar(w))
client_raise(c);
}
if(tags[sel->screen][sel->tag].abovefc && !conf.focus_fmouse)
client_above(sel);
if(c->flags & UrgentFlag)
{
c->flags &= ~UrgentFlag;
tags[c->screen][c->tag].urgent = False;
infobar_draw_taglist(c->screen);
}
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
if(conf.bars.selbar)
infobar_draw_selbar(sel->screen);
}
else
{
XSetInputFocus(dpy, ROOT, RevertToPointerRoot, CurrentTime);
if(conf.bars.selbar)
infobar_draw_selbar(selscreen);
}
return;
}
/* The following functions have the same point :
* find a client member with a Window {{{
*/
/* Get Client with a window */
/** Get a client->win with a window
* \param w Window
* \return The client
*/
Client* client_gb_win(Window w)
{
Client *c;
for(c = clients; c && c->win != w; c = c->next);
return c;
}
/** Get a client->frame with a window
* \param w Window
* \return The client
*/
Client* client_gb_frame(Window w)
{
Client *c;
for(c = clients; c && c->frame != w; c = c->next);
return c;
}
/** Get a client->titlebar with a window
* \param w Window
* \return The client
*/
Client* client_gb_titlebar(Window w)
{
Client *c;
if(!(TBARH - BORDH))
return NULL;
for(c = clients; c && c->titlebar->win != w; c = c->next);
return c;
}
/** Get a client->resize with a window
* \param w Window
* \return The client
*/
Client* client_gb_resize(Window w)
{
Client *c;
for(c = clients; (c && c->resize[Right] != w) && (c && c->resize[Left] != w); c = c->next);
return c;
}
/** Get a client->button[button_num] with a window
* \param w Window
* \param n Pointer who return the button_num
* \return The client
*/
Client* client_gb_button(Window w, int *n)
{
Client *c;
int i;
if(!BUTTONWH || !(TBARH - BORDH))
return NULL;
for(c = clients; c; c = c->next)
for(i = 0; i < conf.titlebar.nbutton; ++i)
if(c->button[i] == w)
{
*n = i;
return c;
}
return NULL;
}
/* }}} */
/** Get a client name
* \param c Client pointer
*/
void
client_get_name(Client *c)
{
Atom rt;
int rf;
ulong ir, il;
IFREE(c->title);
/* This one instead XFetchName for utf8 name support */
if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_name], 0, 4096,
False, net_atom[utf8_string], &rt, &rf, &ir, &il, (uchar**)&c->title) != Success)
XGetWindowProperty(dpy, c->win, ATOM("WM_NAME"), 0, 4096,
False, net_atom[utf8_string], &rt, &rf, &ir, &il, (uchar**)&c->title);
/* If there is no title... */
if(!c->title)
{
XFetchName(dpy, c->win, &(c->title));
if(!c->title)
c->title = _strdup("WMFS");
}
frame_update(c);
if(conf.bars.selbar && c == sel)
infobar_draw_selbar(c->screen);
return;
}
/** Hide a client (for tag switching)
* \param c Client pointer
*/
void
client_hide(Client *c)
{
CHECK(!(c->flags & HideFlag));
client_unmap(c);
c->flags |= HideFlag;
setwinstate(c->win, IconicState);
return;
}
/** Check if the client 'c' is hide
* \param c Client pointer
* \return True if the client is hide; False if not
*/
Bool
ishide(Client *c, int screen)
{
if(((c->tag == seltag[screen] || c->tag == MAXTAG + 1) && c->screen == screen)
|| tags[screen][seltag[screen]].tagad & TagFlag(c->tag))
return False;
return True;
}
/** Kill a client
* \param c Client pointer
*/
void
client_kill(Client *c)
{
XEvent ev;
Atom *atom = NULL;
int proto;
int canbedel = 0;
CHECK(c);
if(XGetWMProtocols(dpy, c->win, &atom, &proto) && atom)
{
while(proto--)
if(atom[proto] == ATOM("WM_DELETE_WINDOW"))
++canbedel;
XFree(atom);
if(canbedel)
{
ev.type = ClientMessage;
ev.xclient.window = c->win;
ev.xclient.message_type = ATOM("WM_PROTOCOLS");
ev.xclient.format = 32;
ev.xclient.data.l[0] = ATOM("WM_DELETE_WINDOW");
ev.xclient.data.l[1] = CurrentTime;
ev.xclient.data.l[2] = 0;
ev.xclient.data.l[3] = 0;
ev.xclient.data.l[4] = 0;
XSendEvent(dpy, c->win, False, NoEventMask, &ev);
}
else
XKillClient(dpy, c->win);
}
else
XKillClient(dpy, c->win);
return;
}
/** Kill the selected client
* \param cmd uicb_t type unused
*/
void
uicb_client_kill(uicb_t cmd)
{
CHECK(sel);
client_kill(sel);
return;
}
/** Map a client
* \param c Client pointer
*/
void
client_map(Client *c)
{
CHECK(c);
if(c->flags & FSSFlag)
XMapWindow(dpy, c->win);
else
{
XMapWindow(dpy, c->frame);
XMapSubwindows(dpy, c->frame);
if(TBARH - BORDH)
{
barwin_map(c->titlebar);
barwin_map_subwin(c->titlebar);
}
XMapSubwindows(dpy, c->frame);
c->flags &= ~UnmapFlag;
}
return;
}
/** Manage a client with a window and his attributes
* \param w Cient's futur Window
* \param wa XWindowAttributes pointer, Window w attributes
* \param ar Do arrange() or not (Bool)
* \return The managed client
*/
Client*
client_manage(Window w, XWindowAttributes *wa, Bool ar)
{
Client *c, *t = NULL;
Window trans, dw;
Status rettrans;
XSetWindowAttributes at;
int mx, my, dint;
uint duint;
screen_get_sel();
c = emalloc(1, sizeof(Client));
c->win = w;
c->screen = selscreen;
c->flags = 0;
XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint);
if(conf.client.place_at_mouse)
{
mx += BORDH;
my += TBARH;
if((MAXW - mx) < wa->width)
mx -= wa->width + BORDH;
if((MAXH - my) < wa->height)
my -= wa->height + TBARH;
}
else
{
mx = wa->x + BORDH;
my = wa->y + TBARH + INFOBARH;
/* Check if the client is already in the selected
* screen, else place the client in it */
if(screen_get_with_geo(mx, my) != selscreen)
{
mx += spgeo[selscreen].x;
my += spgeo[selscreen].y;
}
}
c->ogeo.x = c->geo.x = mx;
c->ogeo.y = c->geo.y = my;
c->ogeo.width = c->geo.width = wa->width;
c->ogeo.height = c->geo.height = wa->height;
c->free_geo = c->geo;
c->tag = seltag[c->screen];
c->layer = (sel && sel->layer > 0) ? sel->layer : 1;
at.event_mask = PropertyChangeMask;
frame_create(c);
client_size_hints(c);
XChangeWindowAttributes(dpy, c->win, CWEventMask, &at);
/* client win should _not_ have borders */
XSetWindowBorderWidth(dpy, c->win, 0);
mouse_grabbuttons(c, False);
/* Transient */
if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
for(t = clients; t && t->win != trans; t = t->next);
if(t)
{
c->tag = t->tag;
c->screen = t->screen;
}
if(!(c->flags & FreeFlag)
&& (rettrans == Success || (c->flags & HintFlag)))
c->flags |= FreeFlag;
free(t);
client_attach(c);
client_get_name(c);
client_map(c);
client_raise(c);
client_focus(c);
setwinstate(c->win, NormalState);
ewmh_get_client_list();
ewmh_manage_window_type(c);
client_set_wanted_tag(c);
client_update_attributes(c);
if(ar)
arrange(c->screen, True);
if(!conf.client.set_new_win_master)
layout_set_client_master(c);
return c;
}
/** Set a geometry with the client size hints
*\param geo Geometry pointer
*\param c Client pointer
*/
void
client_geo_hints(XRectangle *geo, Client *c)
{
/* minimum possible */
if(geo->width < 1)
geo->width = 1;
if(geo->height < 1)
geo->height = 1;
/* base */
geo->width -= c->basew;
geo->height -= c->baseh;
/* aspect */
if(c->minay > 0 && c->maxay > 0
&& c->minax > 0 && c->maxax > 0)
{
if(geo->width * c->maxay > geo->height * c->maxax)
geo->width = geo->height * c->maxax / c->maxay;
else if(geo->width * c->minay < geo->height * c->minax)
geo->height = geo->width * c->minay / c->minax;
}
/* incremental */
if(c->incw)
geo->width -= geo->width % c->incw;
if(c->inch)
geo->height -= geo->height % c->inch;
/* base dimension */
geo->width += c->basew;
geo->height += c->baseh;
if(c->minw > 0 && geo->width < c->minw)
geo->width = c->minw;
if(c->minh > 0 && geo->height < c->minh)
geo->height = c->minh;
if(c->maxw > 0 && geo->width > c->maxw)
geo->width = c->maxw;
if(c->maxh > 0 && geo->height > c->maxh)
geo->height = c->maxh;
return;
}
/** Move and Resize a client
* \param c Client pointer
* \param geo Coordinate info for the future size
* of the client
* \param r Bool for resize hint or not
*/
void
client_moveresize(Client *c, XRectangle geo, Bool r)
{
int os;
if(!c)
return;
os = c->screen;
if(r)
client_geo_hints(&geo, c);
c->flags &= ~MaxFlag;
c->geo = c->ogeo = geo;
if(c->flags & FreeFlag || tags[c->screen][c->tag].layout.func == freelayout)
c->free_geo = geo;
if((c->screen = screen_get_with_geo(c->geo.x, c->geo.y)) != os
&& c->tag != MAXTAG + 1)
c->tag = seltag[c->screen];
frame_moveresize(c, c->geo);
XMoveResizeWindow(dpy, c->win, BORDH, TBARH, c->geo.width, c->geo.height);
client_configure(c);
client_update_attributes(c);
return;
}
/** Maximize a client
* \param c Client pointer
*/
void
client_maximize(Client *c)
{
XRectangle geo;
if(!c || c->flags & FSSFlag)
return;
c->screen = screen_get_with_geo(c->geo.x, c->geo.y);
geo.x = sgeo[c->screen].x;
geo.y = sgeo[c->screen].y;
geo.width = sgeo[c->screen].width - BORDH * 2;
geo.height = sgeo[c->screen].height - BORDH;
client_moveresize(c, geo, False);
return;
}
/** Get client size hints
* \param c Client pointer
*/
void
client_size_hints(Client *c)
{
long msize;
XSizeHints size;
if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
size.flags = PSize;
/* base */
if(size.flags & PBaseSize)
{
c->basew = size.base_width;
c->baseh = size.base_height;
}
else if(size.flags & PMinSize)
{
c->basew = size.min_width;
c->baseh = size.min_height;
}
else
c->basew = c->baseh = 0;
/* inc */
if(size.flags & PResizeInc)
{
c->incw = size.width_inc;
c->inch = size.height_inc;
}
else
c->incw = c->inch = 0;
/* max */
if(size.flags & PMaxSize)
{
c->maxw = size.max_width;
c->maxh = size.max_height;
}
else
c->maxw = c->maxh = 0;
/* min */
if(size.flags & PMinSize)
{
c->minw = (size.min_width ? size.min_width : 1);
c->minh = (size.min_height ? size.min_height: 1);
}
else if(size.flags & PBaseSize)
{
c->minw = (size.base_width ? size.base_width : 1);
c->minh = (size.base_height ? size.base_height : 1);
}
else
c->minw = c->minh = 0;
/* aspect */
if(size.flags & PAspect)
{
c->minax = size.min_aspect.x;
c->maxax = size.max_aspect.x;
c->minay = size.min_aspect.y;
c->maxay = size.max_aspect.y;
}
else
c->minax = c->maxax = c->minay = c->maxay = 0;
if(c->maxw && c->minw && c->maxh && c->minh
&& c->maxw == c->minw && c->maxh == c->minh)
c->flags |= HintFlag;
return;
}
/** Swap two clients
*\param 1 c1 First client
*\param 2 c2 Second client
*/
void
client_swap(Client *c1, Client *c2)
{
/* Check if no one of these clients are free */
CHECK(!(c1->flags & FreeFlag));
CHECK(!(c2->flags & FreeFlag));
if(c1 == c2 || (c1->screen == c2->screen && c1->tag != c2->tag))
return;
/* Swap only the windows */
swap_ptr((void**)&c1->win, (void**)&c2->win);
/* Re-adapt the windows position with its new frame */
XReparentWindow(dpy, c1->win, c1->frame, BORDH, TBARH);
XReparentWindow(dpy, c2->win, c2->frame, BORDH, TBARH);
/* Re-set size hints properties */
client_size_hints(c1);
client_size_hints(c2);
/* Resize the windows */
client_moveresize(c1, c1->geo, False);
client_moveresize(c2, c2->geo, False);
/* Get the new client name */
client_get_name(c1);
client_get_name(c2);
return;
}
/** Set the wanted tag of a client
*\param c Client pointer
*/
void
client_set_wanted_tag(Client *c)
{
XClassHint xch = { 0 };
int i, j, k;
if(conf.ignore_next_client_rules)
{
conf.ignore_next_client_rules = False;
return;
}
XGetClassHint(dpy, c->win, &xch);
for(i = 0; i < screen_count(); ++i)
for(j = 1; j < conf.ntag[i] + 1; ++j)
if(tags[i][j].clients)
for(k = 0; k < tags[i][j].nclients; ++k)
if((xch.res_name && strstr(xch.res_name, tags[i][j].clients[k]))
|| (xch.res_class && strstr(xch.res_class, tags[i][j].clients[k])))
{
c->screen = i;
c->tag = j;
if(c->tag != seltag[selscreen])
{
tags[c->screen][c->tag].request_update = True;
client_focus(NULL);
}
tags[c->screen][c->tag].layout.func(c->screen);
}
return;
}
/** Update client attributes (_WMFS_TAG _WMFS_SCREEN)
*\param c Client pointer
*/
void
client_update_attributes(Client *c)
{
Bool f;
/* For reload use */
XChangeProperty(dpy, c->win, ATOM("_WMFS_TAG"), XA_CARDINAL, 32,
PropModeReplace, (uchar*)&(c->tag), 1);
XChangeProperty(dpy, c->win, ATOM("_WMFS_SCREEN"), XA_CARDINAL, 32,
PropModeReplace, (uchar*)&(c->screen), 1);
f = (c->flags & FreeFlag);
XChangeProperty(dpy, c->win, ATOM("_WMFS_ISFREE"), XA_CARDINAL, 32,
PropModeReplace, (uchar*)&f, 1);
return;
}
/** Raise a client
* \param c Client pointer
*/
void
client_raise(Client *c)
{
if(!c || ((c->flags & TileFlag) && !(c->flags & AboveFlag)))
return;
XRaiseWindow(dpy, c->frame);
return;
}
/** Raise the selected client
* \param cmd uicb_t type unused
*/
void
uicb_client_raise(uicb_t cmd)
{
CHECK(sel);
client_raise(sel);
return;
}
/** UnHide a client (for tag switching)
* \param c Client pointer
*/
void
client_unhide(Client *c)
{
CHECK(c->flags & HideFlag);
client_map(c);
c->flags &= ~HideFlag;
setwinstate(c->win, NormalState);
return;
}
/** Unmanage a client
* \param c Client pointer
*/
void
client_unmanage(Client *c)
{
Client *c_next = NULL;
Bool b = False;
int i;
XGrabServer(dpy);
XSetErrorHandler(errorhandlerdummy);
XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y);
if(sel == c)
client_focus(NULL);
client_detach(c);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
setwinstate(c->win, WithdrawnState);
frame_delete(c);
XSync(dpy, False);
XUngrabServer(dpy);
ewmh_get_client_list();
/* Arrange */
for(i = 0; i < screen_count() && !b; ++i)
if(c->tag == seltag[i])
b = True;
if(b)
tags[c->screen][c->tag].layout.func(c->screen);
else
{
tags[c->screen][c->tag].request_update = True;
infobar_draw(c->screen);
}
XFree(c->title);
/* To focus the previous client */
for(c_next = clients;
c_next && c_next != c->prev
&& c_next->tag != c->tag
&& c_next->screen != c->screen;
c_next = c_next->next);
if(c_next && c_next->tag == seltag[selscreen]
&& c_next->screen == selscreen)
client_focus(c_next);
free(c);
return;
}
/** Unmap a client
* \param c Client pointer
*/
void
client_unmap(Client *c)
{
CHECK(c);
if(c->flags & FSSFlag)
XUnmapWindow(dpy, c->win);
else
{
if(TBARH - BORDH)
{
barwin_unmap_subwin(c->titlebar);
barwin_unmap(c->titlebar);
}
XUnmapWindow(dpy, c->frame);
XUnmapSubwindows(dpy, c->frame);
c->flags |= UnmapFlag;
}
return;
}
/** Set the client screen
*\param c Client pointer
*\param s Screen id
*/
void
client_set_screen(Client *c, int s)
{
int os;
XRectangle geo;
if(!c || s < 0 || s > screen_count() - 1 || s == c->screen)
return;
/* Save old client screen/geo to arrange */
geo = c->geo;
os = c->screen;
c->screen = s;
c->tag = seltag[s];
/* Arrange */
if(tags[s][seltag[s]].layout.func == freelayout
|| tags[s][seltag[s]].layout.func == maxlayout
|| tags[os][seltag[os]].layout.func == freelayout
|| tags[os][seltag[os]].layout.func == maxlayout)
{
geo.x = (sgeo[s].x + sgeo[s].width / 2) - (c->geo.width / 2);
geo.y = (sgeo[s].y + sgeo[s].height / 2) - (c->geo.height / 2);
client_moveresize(c, geo, False);
}
arrange(s, True);
arrange(os, True);
if(!(c->flags & TileFlag))
{
client_focus(c);
client_raise(c);
}
return;
}
/** Change client of screen to next screen
* \param cmd uicb_t type unused
*/
void
uicb_client_screen_next(uicb_t cmd)
{
CHECK(sel);
client_set_screen(sel, (sel->screen + 1 > screen_count() - 1) ? 0 : sel->screen + 1);
return;
}
/** Change client of screen to prev screen
* \param cmd uicb_t type unused
*/
void
uicb_client_screen_prev(uicb_t cmd)
{
CHECK(sel);
client_set_screen(sel, (sel->screen - 1 < 0) ? screen_count() - 1 : sel->screen - 1);
return;
}
/** Move a client
*\param cmd uicb_t type
*/
void
uicb_client_move(uicb_t cmd)
{
XRectangle geo;
int xi = 0, yi = 0;
if((sel->flags & TileFlag)
|| (sel->flags & MaxFlag)
|| (sel->flags & LMaxFlag)
|| (sel->flags & FSSFlag)
|| !sel)
return;
geo = sel->geo;
if(sscanf(cmd, "%d %d", &xi, &yi))
{
geo.x += xi;
geo.y += yi;
client_moveresize(sel, geo, False);
}
return;
}
/** Resize a client
*\param cmd uicb_t type
*/
void
uicb_client_resize(uicb_t cmd)
{
XRectangle geo;
int wi = 0, hi = 0;
if((sel->flags & TileFlag)
|| (sel->flags & MaxFlag)
|| (sel->flags & LMaxFlag)
|| (sel->flags & FSSFlag)
|| !sel)
return;
geo = sel->geo;
if(sscanf(cmd, "%d %d", &wi, &hi))
{
geo.width += ((geo.width + wi > sel->minw && geo.width + wi < 65536) ? wi : 0);
geo.height += ((geo.height + hi > sel->minh && geo.height + hi < 65536) ? hi : 0);
client_moveresize(sel, geo, False);
}
return;
}
/** Ignore next client rules
*\param cmd uicb_t type
*/
void
uicb_ignore_next_client_rules(uicb_t cmd)
{
conf.ignore_next_client_rules = !conf.ignore_next_client_rules;
return;
}
/** Show clientlist menu
*\param cmd uicb_t type
*/
void
uicb_clientlist(uicb_t cmd)
{
int i, d, u, x, y;
int n = 0;
Window w;
Client *c = NULL;
screen_get_sel();
for(c = clients; c; c = c->next)
if(!ishide(c, selscreen))
++n;
if(n > 0)
{
if(clientlist.nitem)
menu_clear(&clientlist);
menu_init(&clientlist, "clientlist", n,
/* Colors */
conf.colors.tagselbg,
conf.colors.tagselfg,
conf.colors.bar,
conf.colors.text);
for(i = 0, c = clients; c; c = c->next)
if(!ishide(c, selscreen))
{
sprintf(clist_index[i].key, "%d", i);
clist_index[i].client = c;
menu_new_item(&clientlist.item[i], c->title,
uicb_client_select, clist_index[i].key);
if(c == sel)
clientlist.item[i].check = name_to_func("check_clist", func_list);
i++;
}
clist_index[i].client = NULL;
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&u);
menu_draw(clientlist, x, y);
}
return;
}
/** Select client
*\param cmd uicb_t type clientlist index
*/
void
uicb_client_select(uicb_t cmd)
{
int i;
Window w;
int d, x, y;
for(i = 0; i < MAXCLIST && clist_index[i].client; ++i)
if(!strcmp(cmd, clist_index[i].key))
{
client_focus(clist_index[i].client);
client_raise(clist_index[i].client);
/* Move pointer on client */
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&d);
XWarpPointer(dpy, ROOT, ROOT, x, y, d, d,
clist_index[i].client->geo.x + clist_index[i].client->geo.width / 2,
clist_index[i].client->geo.y + clist_index[i].client->geo.height / 2);
}
return;
}
/** Check clientlist menu fake function
* \param cmd uicb_t type unused
*/
Bool
uicb_checkclist(uicb_t cmd)
{
return True;
}
/** Set selected client on all tag (ignore tags
*\para cmd uicb_t type unused
*/
void
uicb_client_ignore_tag(uicb_t cmd)
{
CHECK(sel);
screen_get_sel();
sel->tag = ((sel->tag == MAXTAG + 1) ? seltag[selscreen] : MAXTAG + 1);
arrange(sel->screen, True);
return;
}