/*
* ion/ioncore/clientwin.c
*
- * Copyright (c) Tuomo Valkonen 1999-2007.
+ * Copyright (c) Tuomo Valkonen 1999-2008.
*
- * 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 <string.h>
#include "bindmaps.h"
#include "return.h"
#include "conf.h"
+#include "group.h"
static void set_clientwin_state(WClientWin *cwin, int state);
}
-#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;
+ char *s;
int i1, i2;
tab=ioncore_get_winprop(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;
-#if 0
- cwin->szplcy=get_sizepolicy_winprop(cwin, "sizepolicy",
- SIZEPOLICY_DEFAULT);
- cwin->transient_szplcy=get_sizepolicy_winprop(cwin,
- "transient_sizepolicy",
- DFLT_SZPLCY);
-#endif
+ if(extl_table_gets_s(tab, "orientation", &s)){
+ if(strcmp(s, "vertical")==0)
+ cwin->flags|=CLIENTWIN_PROP_O_VERT;
+ else if(strcmp(s, "horizontal")==0)
+ cwin->flags|=CLIENTWIN_PROP_O_HORIZ;
+ free(s);
+ }
}
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;
+ }
}
set_sane_gravity(cwin->win);
- cwin->transient_for=None;
-
cwin->n_cmapwins=0;
cwin->cmap=attr->colormap;
cwin->cmaps=NULL;
param.dockapp=FALSE;
-again:
/* Is the window already being managed? */
cwin=XWINDOW_REGION_OF_T(win, WClientWin);
if(cwin!=NULL)
*/
xwindow_unmanaged_selectinput(win, StructureNotifyMask);
+ if(!XGetWindowAttributes(ioncore_g.dpy, win, &attr)){
+ if(maprq)
+ warn(TR("Window %#x disappeared."), win);
+ goto fail2;
+ }
/* Is it a dockapp?
*/
hints=XGetWMHints(ioncore_g.dpy, win);
-
- if(hints!=NULL && hints->flags&StateHint)
- init_state=hints->initial_state;
- if(!param.dockapp && init_state==WithdrawnState &&
- hints->flags&IconWindowHint && hints->icon_window!=None){
- /* The dockapp might be displaying its "main" window if no
- * wm that understands dockapps has been managing it.
- */
- if(!maprq)
- XUnmapWindow(ioncore_g.dpy, win);
-
- xwindow_unmanaged_selectinput(win, 0);
-
- win=hints->icon_window;
+ if(hints!=NULL){
+ if(hints->flags&StateHint)
+ init_state=hints->initial_state;
+
+ if(!param.dockapp && init_state==WithdrawnState &&
+ hints->flags&IconWindowHint && hints->icon_window!=None){
+ Window icon_win=hints->icon_window;
+ XWindowAttributes icon_attr;
+
+ if(!XGetWindowAttributes(ioncore_g.dpy, icon_win, &icon_attr)){
+ if(maprq)
+ warn(TR("Window %#x disappeared."), win);
+ XFree((void*)hints);
+ goto fail2;
+ }
+
+ if(!maprq){
+ if(attr.map_state==IsViewable){
+ /* The dockapp might be displaying its "main" window if no
+ * wm that understands dockapps has been managing it.
+ */
+ XUnmapWindow(ioncore_g.dpy, win);
+ param.dockapp=TRUE;
+ }else{
+ /* Main window is unmapped on initial scan, but icon window
+ * is mapped. Let's hope it's a dockapp left by e.g. us.
+ */
+ if(icon_attr.map_state==IsViewable)
+ param.dockapp=TRUE;
+ }
+ }else{
+ param.dockapp=TRUE;
+ }
+
+ if(param.dockapp){
+ char **p=NULL;
+ int n=0;
+
+ xwindow_unmanaged_selectinput(win, 0);
+ xwindow_unmanaged_selectinput(icon_win, StructureNotifyMask);
+
+ win=icon_win;
+ attr=icon_attr;
+
+ /* Copy WM_CLASS as _ION_DOCKAPP_HACK */
+
+ p=xwindow_get_text_property(win, XA_WM_CLASS, &n);
+
+ if(p!=NULL){
+ xwindow_set_text_property(icon_win, ioncore_g.atom_dockapp_hack,
+ (const char **)p, n);
+ XFreeStringList(p);
+ }else{
+ const char *pdummy[2]={"unknowndockapp", "UnknownDockapp"};
+ xwindow_set_text_property(icon_win, ioncore_g.atom_dockapp_hack,
+ pdummy, 2);
+ }
+ }
+ }
- /* It is a dockapp, do everything again from the beginning, now
- * with the icon window.
- */
- param.dockapp=TRUE;
- goto again;
- }
-
- if(hints!=NULL)
XFree((void*)hints);
-
- if(!XGetWindowAttributes(ioncore_g.dpy, win, &attr)){
- if(maprq)
- warn(TR("Window %#x disappeared."), win);
- goto fail2;
}
- attr.width=maxof(attr.width, 1);
- attr.height=maxof(attr.height, 1);
-
/* Do we really want to manage it? */
if(!param.dockapp && (attr.override_redirect ||
(!maprq && attr.map_state!=IsViewable))){
goto fail2;
}
+ attr.width=maxof(attr.width, 1);
+ attr.height=maxof(attr.height, 1);
+
/* Find root window */
FOR_ALL_ROOTWINS(rootwin){
if(WROOTWIN_ROOT(rootwin)==attr.root)
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
: 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
static void clientwin_do_unmapped(WClientWin *cwin, Window win)
{
- region_dispose_((WRegion*)cwin);
+ cwin->flags|=CLIENTWIN_UNMAP_RQ;
+
+ /* 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);
}
/*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)
}
-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
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;
}
}
}
+static int clientwin_orientation(WClientWin *cwin)
+{
+ return (cwin->flags&CLIENTWIN_PROP_O_VERT
+ ? REGION_ORIENTATION_VERTICAL
+ : (cwin->flags&CLIENTWIN_PROP_O_HORIZ
+ ? REGION_ORIENTATION_HORIZONTAL
+ : REGION_ORIENTATION_NONE));
+}
+
+
/*}}}*/
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)
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);
/*{{{ 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;
}
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){
}
+static void do_sm(ExtlTab tab)
+{
+ SMAddCallback *add_cb;
+ SMCfgCallback *cfg_cb;
+ WPHolder *ph;
+
+ ioncore_get_sm_callbacks(&add_cb, &cfg_cb);
+
+ if(add_cb!=NULL){
+ ph=ioncore_get_load_pholder();
+
+ if(ph!=NULL){
+ if(!add_cb(ph, tab))
+ destroy_obj((Obj*)ph);
+ }
+ }
+}
+
+
WRegion *clientwin_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
{
double wind=0;
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;
&real_chkc);
if(!got_chkc || real_chkc!=chkc){
- ioncore_clientwin_load_missing();
+ do_sm(tab);
return NULL;
}
return NULL;
}
+ if(attr.root!=region_root_of((WRegion*)par))
+ return NULL;
+
if(attr.override_redirect ||
(ioncore_g.opmode==IONCORE_OPMODE_INIT && attr.map_state!=IsViewable)){
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)
{region_size_hints,
clientwin_size_hints},
+
+ {(DynFun*)region_orientation,
+ (DynFun*)clientwin_orientation},
{(DynFun*)region_rqclose,
(DynFun*)clientwin_rqclose},