12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151 |
- /*
- * 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)
- 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)
- 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, False);
- }
- 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);
- 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 function 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;
- /* 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->screen == screen)
- 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);
- XSetWindowBorderWidth(dpy, c->win, 0); /* client win sould _not_ have borders */
- mouse_grabbuttons(c, False);
- if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
- for(t = clients; t && t->win != trans; t = t->next);
- if(t)
- c->tag = t->tag;
- 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->screen = screen_get_with_geo(c->geo.x, c->geo.y)) != os)
- 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;
- 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) ? True : False;
- 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)
- {
- 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;
- }
|