X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=ioncore%2Fclientwin.c;h=35164de70388ada767bc3a32a7711a96b255fbcb;hb=ae4260bb64817c11f9a7140324cd3e3ba113e297;hp=4b4dbe4a56ab4011a5f28071b9d3a423e0f00855;hpb=8366314611bf30a0f31d25bf5f5023186fa87692;p=ion3.git diff --git a/ioncore/clientwin.c b/ioncore/clientwin.c index 4b4dbe4..35164de 100644 --- a/ioncore/clientwin.c +++ b/ioncore/clientwin.c @@ -1,12 +1,9 @@ /* * ion/ioncore/clientwin.c * - * Copyright (c) Tuomo Valkonen 1999-2006. + * Copyright (c) Tuomo Valkonen 1999-2007. * - * Ion is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * See the included file LICENSE for details. */ #include @@ -41,6 +38,9 @@ #include "netwm.h" #include "xwindow.h" #include "bindmaps.h" +#include "return.h" +#include "conf.h" +#include "group.h" static void set_clientwin_state(WClientWin *cwin, int state); @@ -78,22 +78,6 @@ void clientwin_get_protocols(WClientWin *cwin) } -static bool get_winprop_fn_set=FALSE; -static ExtlFn get_winprop_fn; - -/*EXTL_DOC - * Set function used to look up winprops. - */ -EXTL_EXPORT -void ioncore_set_get_winprop_fn(ExtlFn fn) -{ - if(get_winprop_fn_set) - extl_unref_fn(get_winprop_fn); - get_winprop_fn=extl_ref_fn(fn); - get_winprop_fn_set=TRUE; -} - - static WSizePolicy get_sizepolicy_winprop(WClientWin *cwin, const char *propname, WSizePolicy value) @@ -108,27 +92,38 @@ static WSizePolicy get_sizepolicy_winprop(WClientWin *cwin, } -#define SIZEHINT_PROPS (CLIENTWIN_PROP_MAXSIZE| \ - CLIENTWIN_PROP_MINSIZE| \ - CLIENTWIN_PROP_ASPECT| \ - CLIENTWIN_PROP_IGNORE_RSZINC) +#define SIZEHINT_PROPS (CLIENTWIN_PROP_MAXSIZE| \ + CLIENTWIN_PROP_MINSIZE| \ + CLIENTWIN_PROP_ASPECT| \ + CLIENTWIN_PROP_RSZINC| \ + CLIENTWIN_PROP_I_MAXSIZE| \ + CLIENTWIN_PROP_I_MINSIZE| \ + CLIENTWIN_PROP_I_ASPECT| \ + CLIENTWIN_PROP_I_RSZINC) + + +#define DO_SZH(NAME, FLAG, IFLAG, SZHFLAG, W, H, C) \ + if(extl_table_is_bool_set(tab, "ignore_" NAME)){ \ + cwin->flags|=IFLAG; \ + }else if(extl_table_gets_t(tab, NAME, &tab2)){ \ + if(extl_table_gets_i(tab2, "w", &i1) && \ + extl_table_gets_i(tab2, "h", &i2)){ \ + cwin->size_hints.W=i1; \ + cwin->size_hints.H=i2; \ + C \ + cwin->size_hints.flags|=SZHFLAG; \ + cwin->flags|=FLAG; \ + } \ + extl_unref_table(tab2); \ + } static void clientwin_get_winprops(WClientWin *cwin) { ExtlTab tab, tab2; int i1, i2; - bool ret; - - if(!get_winprop_fn_set) - return; - extl_protect(NULL); - ret=extl_call(get_winprop_fn, "o", "t", cwin, &tab); - extl_unprotect(NULL); - - if(!ret) - return; + tab=ioncore_get_winprop(cwin); cwin->proptab=tab; @@ -141,44 +136,21 @@ static void clientwin_get_winprops(WClientWin *cwin) if(extl_table_is_bool_set(tab, "acrobatic")) cwin->flags|=CLIENTWIN_PROP_ACROBATIC; - if(extl_table_gets_t(tab, "max_size", &tab2)){ - if(extl_table_gets_i(tab2, "w", &i1) && - extl_table_gets_i(tab2, "h", &i2)){ - cwin->size_hints.max_width=i1; - cwin->size_hints.max_height=i2; - cwin->size_hints.flags|=PMaxSize; - cwin->flags|=CLIENTWIN_PROP_MAXSIZE; - } - extl_unref_table(tab2); - } - - if(extl_table_gets_t(tab, "min_size", &tab2)){ - if(extl_table_gets_i(tab2, "w", &i1) && - extl_table_gets_i(tab2, "h", &i2)){ - cwin->size_hints.min_width=i1; - cwin->size_hints.min_height=i2; - cwin->size_hints.flags|=PMinSize; - cwin->flags|=CLIENTWIN_PROP_MINSIZE; - } - extl_unref_table(tab2); - } - - if(extl_table_gets_t(tab, "aspect", &tab2)){ - if(extl_table_gets_i(tab2, "w", &i1) && - extl_table_gets_i(tab2, "h", &i2)){ - cwin->size_hints.min_aspect.x=i1; - cwin->size_hints.max_aspect.x=i1; - cwin->size_hints.min_aspect.y=i2; - cwin->size_hints.max_aspect.y=i2; - cwin->size_hints.flags|=PAspect; - cwin->flags|=CLIENTWIN_PROP_ASPECT; - } - extl_unref_table(tab2); - } - - if(extl_table_is_bool_set(tab, "ignore_resizeinc")) - cwin->flags|=CLIENTWIN_PROP_IGNORE_RSZINC; - + DO_SZH("max_size", CLIENTWIN_PROP_MAXSIZE, CLIENTWIN_PROP_I_MAXSIZE, + PMaxSize, max_width, max_height, ); + + DO_SZH("min_size", CLIENTWIN_PROP_MINSIZE, CLIENTWIN_PROP_I_MINSIZE, + PMinSize, min_width, min_height, ); + + DO_SZH("resizeinc", CLIENTWIN_PROP_RSZINC, CLIENTWIN_PROP_I_RSZINC, + PResizeInc, width_inc, height_inc, ); + + DO_SZH("aspect", CLIENTWIN_PROP_ASPECT, CLIENTWIN_PROP_I_ASPECT, + PAspect, min_aspect.x, min_aspect.y, + { cwin->size_hints.max_aspect.x=i1; + cwin->size_hints.max_aspect.y=i2; + }); + if(extl_table_is_bool_set(tab, "ignore_cfgrq")) cwin->flags|=CLIENTWIN_PROP_IGNORE_CFGRQ; @@ -198,26 +170,37 @@ void clientwin_get_size_hints(WClientWin *cwin) xwindow_get_sizehints(cwin->win, &(cwin->size_hints)); - if(cwin->flags&CLIENTWIN_PROP_MAXSIZE){ + if(cwin->flags&CLIENTWIN_PROP_I_MAXSIZE){ + cwin->size_hints.flags&=~PMaxSize; + }else if(cwin->flags&CLIENTWIN_PROP_MAXSIZE){ cwin->size_hints.max_width=tmp.max_width; cwin->size_hints.max_height=tmp.max_height; cwin->size_hints.flags|=PMaxSize; } - - if(cwin->flags&CLIENTWIN_PROP_MINSIZE){ + + if(cwin->flags&CLIENTWIN_PROP_I_MINSIZE){ + cwin->size_hints.flags&=~PMinSize; + }else if(cwin->flags&CLIENTWIN_PROP_MINSIZE){ cwin->size_hints.min_width=tmp.min_width; cwin->size_hints.min_height=tmp.min_height; cwin->size_hints.flags|=PMinSize; } - if(cwin->flags&CLIENTWIN_PROP_ASPECT){ + if(cwin->flags&CLIENTWIN_PROP_I_ASPECT){ + cwin->size_hints.flags&=~PAspect; + }else if(cwin->flags&CLIENTWIN_PROP_ASPECT){ cwin->size_hints.min_aspect=tmp.min_aspect; cwin->size_hints.max_aspect=tmp.max_aspect; cwin->size_hints.flags|=PAspect; } - if(cwin->flags&CLIENTWIN_PROP_IGNORE_RSZINC) + if(cwin->flags&CLIENTWIN_PROP_I_RSZINC){ cwin->size_hints.flags&=~PResizeInc; + }else if(cwin->flags&CLIENTWIN_PROP_RSZINC){ + cwin->size_hints.width_inc=tmp.width_inc; + cwin->size_hints.height_inc=tmp.height_inc; + cwin->size_hints.flags|=PResizeInc; + } } @@ -337,8 +320,6 @@ static bool clientwin_init(WClientWin *cwin, WWindow *par, Window win, set_sane_gravity(cwin->win); - cwin->transient_for=None; - cwin->n_cmapwins=0; cwin->cmap=attr->colormap; cwin->cmaps=NULL; @@ -346,8 +327,6 @@ static bool clientwin_init(WClientWin *cwin, WWindow *par, Window win, cwin->n_cmapwins=0; cwin->event_mask=IONCORE_EVENTMASK_CLIENTWIN; - cwin->fs_pholder=NULL; - region_init(&(cwin->region), par, &fp); cwin->region.flags|=REGION_GRAB_ON_PARENT; @@ -376,26 +355,6 @@ static WClientWin *create_clientwin(WWindow *par, Window win, } -static bool handle_target_prop(WClientWin *cwin, const WManageParams *param) -{ - WRegion *r=NULL; - char *target_name=NULL; - - if(extl_table_gets_s(cwin->proptab, "target", &target_name)){ - r=ioncore_lookup_region(target_name, NULL); - - free(target_name); - - if(r!=NULL){ - if(region_manage_clientwin(r, cwin, param, - MANAGE_REDIR_PREFER_NO)) - return TRUE; - } - } - - return FALSE; -} - WClientWin *clientwin_get_transient_for(const WClientWin *cwin) { @@ -484,6 +443,7 @@ WClientWin* ioncore_manage_clientwin(Window win, bool maprq) XWMHints *hints; int init_state=NormalState; WManageParams param=MANAGEPARAMS_INIT; + void *mrshpm[2]; param.dockapp=FALSE; @@ -516,11 +476,30 @@ again: xwindow_unmanaged_selectinput(win, 0); - win=hints->icon_window; + /* Copy WM_CLASS as _ION_DOCKAPP_HACK */ + { + char **p=NULL; + int n=0; + + p=xwindow_get_text_property(win, XA_WM_CLASS, &n); + + if(p!=NULL){ + xwindow_set_text_property(hints->icon_window, + ioncore_g.atom_dockapp_hack, + (const char **)p, n); + XFreeStringList(p); + }else{ + const char *pdummy[2]={"unknowndockapp", "UnknownDockapp"}; + xwindow_set_text_property(hints->icon_window, + ioncore_g.atom_dockapp_hack, + pdummy, 2); + } + } /* It is a dockapp, do everything again from the beginning, now * with the icon window. */ + win=hints->icon_window; param.dockapp=TRUE; goto again; } @@ -564,7 +543,6 @@ again: param.geom=REGION_GEOM(cwin); param.maprq=maprq; - param.userpos=(cwin->size_hints.flags&USPosition); param.switchto=(init_state!=IconicState && clientwin_get_switchto(cwin)); param.jumpto=extl_table_is_bool_set(cwin->proptab, "jumpto"); param.gravity=(cwin->size_hints.flags&PWinGravity @@ -572,6 +550,9 @@ again: : ForgetGravity); param.tfor=clientwin_get_transient_for(cwin); + if(!extl_table_gets_b(cwin->proptab, "userpos", ¶m.userpos)) + param.userpos=(cwin->size_hints.flags&USPosition); + if(cwin->flags&SIZEHINT_PROPS){ /* If size hints have been messed with, readjust requested geometry * here. If programs themselves give incompatible geometries and @@ -581,21 +562,14 @@ again: FALSE); } - if(!handle_target_prop(cwin, ¶m)){ - bool managed; - void *mrshpm[2]; - - mrshpm[0]=cwin; - mrshpm[1]=¶m; + mrshpm[0]=cwin; + mrshpm[1]=¶m; - managed=hook_call_alt(clientwin_do_manage_alt, &mrshpm, - (WHookMarshall*)do_manage_mrsh, - (WHookMarshallExtl*)do_manage_mrsh_extl); - - if(!managed){ - warn(TR("Unable to manage client window %#x."), win); - goto failure; - } + if(!hook_call_alt(clientwin_do_manage_alt, &mrshpm, + (WHookMarshall*)do_manage_mrsh, + (WHookMarshallExtl*)do_manage_mrsh_extl)){ + warn(TR("Unable to manage client window %#x."), win); + goto failure; } if(ioncore_g.opmode==IONCORE_OPMODE_NORMAL && @@ -604,7 +578,6 @@ again: region_set_activity((WRegion*)cwin, SETPARAM_SET); } - if(postmanage_check(cwin, &attr)){ if(param.jumpto && ioncore_g.focus_next==NULL) region_goto((WRegion*)cwin); @@ -696,6 +669,8 @@ void clientwin_deinit(WClientWin *cwin) WRegion *reg; if(cwin->win!=None){ + region_pointer_focus_hack(&cwin->region); + xwindow_unmanaged_selectinput(cwin->win, 0); XUnmapWindow(ioncore_g.dpy, cwin->win); @@ -721,12 +696,6 @@ void clientwin_deinit(WClientWin *cwin) clientwin_clear_colormaps(cwin); - if(cwin->fs_pholder!=NULL){ - WPHolder *ph=cwin->fs_pholder; - cwin->fs_pholder=NULL; - destroy_obj((Obj*)ph); - } - region_deinit((WRegion*)cwin); } @@ -747,12 +716,13 @@ static bool mrsh_u_extl(ExtlFn fn, void *param) static void clientwin_do_unmapped(WClientWin *cwin, Window win) { - bool mcf=region_may_control_focus((WRegion*)cwin); - - if(mcf && cwin->fs_pholder!=NULL) - pholder_goto(cwin->fs_pholder); + cwin->flags|=CLIENTWIN_UNMAP_RQ; - destroy_obj((Obj*)cwin); + /* First try a graceful chain-dispose */ + if(!region_rqdispose((WRegion*)cwin)){ + /* But force dispose anyway */ + region_dispose((WRegion*)cwin); + } hook_call(clientwin_unmapped_hook, &win, mrsh_u_c, mrsh_u_extl); } @@ -798,8 +768,8 @@ static bool send_clientmsg(Window win, Atom a, Time stmp) /*EXTL_DOC - * Attempt to kill (with XKillWindow) the client that owns the X - * window correspoding to \var{cwin}. + * Attempt to kill (with \code{XKillWindow}) the client that owns + * the X window correspoding to \var{cwin}. */ EXTL_EXPORT_MEMBER void clientwin_kill(WClientWin *cwin) @@ -808,7 +778,7 @@ void clientwin_kill(WClientWin *cwin) } -bool clientwin_rqclose(WClientWin *cwin, bool relocate_ignored) +void clientwin_rqclose(WClientWin *cwin, bool relocate_ignored) { /* Ignore relocate parameter -- client windows can always be * destroyed by the application in any case, so way may just as @@ -818,10 +788,8 @@ bool clientwin_rqclose(WClientWin *cwin, bool relocate_ignored) if(cwin->flags&CLIENTWIN_P_WM_DELETE){ send_clientmsg(cwin->win, ioncore_g.atom_wm_delete, ioncore_get_timestamp()); - return TRUE; }else{ warn(TR("Client does not support the WM_DELETE protocol.")); - return FALSE; } } @@ -843,6 +811,8 @@ static void set_clientwin_state(WClientWin *cwin, int state) static void hide_clientwin(WClientWin *cwin) { + region_pointer_focus_hack(&cwin->region); + if(cwin->flags&CLIENTWIN_PROP_ACROBATIC){ XMoveWindow(ioncore_g.dpy, cwin->win, -2*REGION_GEOM(cwin).w, -2*REGION_GEOM(cwin).h); @@ -981,15 +951,8 @@ static bool clientwin_fitrep(WClientWin *cwin, WWindow *np, region_set_parent((WRegion*)cwin, np); sendconfig_clientwin(cwin); - if(!REGION_IS_FULLSCREEN(cwin) && cwin->fs_pholder!=NULL){ - WPHolder *ph=cwin->fs_pholder; - cwin->fs_pholder=NULL; + if(!REGION_IS_FULLSCREEN(cwin)) cwin->flags&=~CLIENTWIN_FS_RQ; - /* Can't destroy it yet - messes up mplex placeholder - * reorganisation. - */ - mainloop_defer_destroy((Obj*)ph); - } netwm_update_state(cwin); } @@ -1092,12 +1055,27 @@ EXTL_SAFE EXTL_EXPORT_MEMBER ExtlTab clientwin_get_ident(WClientWin *cwin) { - char **p=NULL, *wrole=NULL; + char **p=NULL, **p2=NULL, *wrole=NULL; int n=0, n2=0, n3=0, tmp=0; + Window tforwin=None; ExtlTab tab; + bool dockapp_hack=FALSE; p=xwindow_get_text_property(cwin->win, XA_WM_CLASS, &n); - wrole=xwindow_get_string_property(cwin->win, ioncore_g.atom_wm_window_role, &n2); + + p2=xwindow_get_text_property(cwin->win, ioncore_g.atom_dockapp_hack, &n2); + + dockapp_hack=(n2>0); + + if(p==NULL){ + /* Some dockapps do actually have WM_CLASS, so use it. */ + p=p2; + n=n2; + p2=NULL; + } + + wrole=xwindow_get_string_property(cwin->win, ioncore_g.atom_wm_window_role, + &n3); tab=extl_create_table(); if(n>=2 && p[1]!=NULL) @@ -1107,8 +1085,18 @@ ExtlTab clientwin_get_ident(WClientWin *cwin) if(wrole!=NULL) extl_table_sets_s(tab, "role", wrole); + if(XGetTransientForHint(ioncore_g.dpy, cwin->win, &tforwin) + && tforwin!=None){ + extl_table_sets_b(tab, "is_transient", TRUE); + } + + if(dockapp_hack) + extl_table_sets_b(tab, "is_dockapp", TRUE); + if(p!=NULL) XFreeStringList(p); + if(p2!=NULL) + XFreeStringList(p2); if(wrole!=NULL) free(wrole); @@ -1122,26 +1110,31 @@ ExtlTab clientwin_get_ident(WClientWin *cwin) /*{{{ ConfigureRequest */ -void clientwin_handle_configure_request(WClientWin *cwin, - XConfigureRequestEvent *ev) +static bool check_fs_cfgrq(WClientWin *cwin, XConfigureRequestEvent *ev) { - if(ev->value_mask&CWBorderWidth) - cwin->orig_bw=ev->border_width; - - if(cwin->flags&CLIENTWIN_PROP_IGNORE_CFGRQ){ - sendconfig_clientwin(cwin); - return; - } - /* check full screen request */ if((ev->value_mask&(CWWidth|CWHeight))==(CWWidth|CWHeight)){ - bool sw=clientwin_fullscreen_may_switchto(cwin); - if(clientwin_check_fullscreen_request(cwin, ev->width, ev->height, sw)) - return; + WRegion *grp=region_groupleader_of((WRegion*)cwin); + WScreen *scr=clientwin_fullscreen_chkrq(cwin, ev->width, ev->height); + + if(scr!=NULL && REGION_MANAGER(grp)!=(WRegion*)scr){ + bool sw=clientwin_fullscreen_may_switchto(cwin); + + cwin->flags|=CLIENTWIN_FS_RQ; + + if(!region_fullscreen_scr(grp, scr, sw)) + cwin->flags&=~CLIENTWIN_FS_RQ; + + return TRUE; + } } - cwin->flags|=CLIENTWIN_NEED_CFGNTFY; + return FALSE; +} + +static bool check_normal_cfgrq(WClientWin *cwin, XConfigureRequestEvent *ev) +{ if(ev->value_mask&(CWX|CWY|CWWidth|CWHeight)){ WRQGeomParams rq=RQGEOMPARAMS_INIT; int gdx=0, gdy=0; @@ -1196,6 +1189,25 @@ void clientwin_handle_configure_request(WClientWin *cwin, } region_rqgeom((WRegion*)cwin, &rq, NULL); + + return TRUE; + } + + return FALSE; +} + + +void clientwin_handle_configure_request(WClientWin *cwin, + XConfigureRequestEvent *ev) +{ + if(ev->value_mask&CWBorderWidth) + cwin->orig_bw=ev->border_width; + + cwin->flags|=CLIENTWIN_NEED_CFGNTFY; + + if(!(cwin->flags&CLIENTWIN_PROP_IGNORE_CFGRQ)){ + if(!check_fs_cfgrq(cwin, ev)) + check_normal_cfgrq(cwin, ev); } if(cwin->flags&CLIENTWIN_NEED_CFGNTFY){ @@ -1287,8 +1299,8 @@ WRegion *clientwin_load(WWindow *par, const WFitParams *fp, ExtlTab tab) WClientWin *cwin=NULL; XWindowAttributes attr; WRectangle rg; - bool got_chkc; - + bool got_chkc=FALSE; + if(!extl_table_gets_d(tab, "windowid", &wind) || !extl_table_gets_i(tab, "checkcode", &chkc)){ return NULL; @@ -1321,14 +1333,7 @@ WRegion *clientwin_load(WWindow *par, const WFitParams *fp, ExtlTab tab) warn(TR("Saved client window does not want to be managed.")); return NULL; } - - /* - attr.x=fp->g.x; - attr.y=fp->g.y; - attr.width=fp->g.w; - attr.height=fp->g.h; - */ - + cwin=create_clientwin(par, win, &attr); if(cwin==NULL)