X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/src/client.c diff --git a/src/client.c b/src/client.c dissimilarity index 85% index 14ec9d14..1fdab42a 100644 --- a/src/client.c +++ b/src/client.c @@ -1,801 +1,768 @@ -/* - * Window Maker window manager - * - * Copyright (c) 1997-2003 Alfredo K. Kojima - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#include "wconfig.h" - -#include -#include -#include -#ifdef SHAPE -#include -#endif - -#include -#include -#include - -#include "WindowMaker.h" -#include "wcore.h" -#include "framewin.h" -#include "window.h" -#include "properties.h" -#include "actions.h" -#include "icon.h" -#include "client.h" -#include "funcs.h" -#include "stacking.h" -#include "appicon.h" -#include "appmenu.h" -#ifdef NETWM_HINTS -# include "wmspec.h" -#endif - - -/****** Global Variables ******/ - -/* contexts */ -extern XContext wWinContext; - -extern Atom _XA_WM_STATE; -extern Atom _XA_WM_PROTOCOLS; -extern Atom _XA_WM_COLORMAP_WINDOWS; - -extern Atom _XA_WINDOWMAKER_MENU; - -extern Atom _XA_GNUSTEP_WM_ATTR; -extern Atom _XA_GNUSTEP_WM_RESIZEBAR; - -#ifdef SHAPE -extern Bool wShapeSupported; -#endif - - -/* - *-------------------------------------------------------------------- - * wClientRestore-- - * Reparent the window back to the root window. - * - *-------------------------------------------------------------------- - */ -void -wClientRestore(WWindow *wwin) -{ -#if 0 - int gx, gy; - - wClientGetGravityOffsets(wwin, &gx, &gy); - /* set the positio of the frame on screen */ - wwin->frame_x -= gx * FRAME_BORDER_WIDTH; - wwin->frame_y -= gy * FRAME_BORDER_WIDTH; - /* if gravity is to the south, account for the border sizes */ - if (gy > 0) - wwin->frame_y += (wwin->frame->top_width + wwin->frame->bottom_width); -#endif - XSetWindowBorderWidth(dpy, wwin->client_win, wwin->old_border_width); - XReparentWindow(dpy, wwin->client_win, wwin->screen_ptr->root_win, - wwin->frame_x, wwin->frame_y); - - /* don't let the window get iconified after restart */ - /* - if (wwin->flags.shaded) - wClientSetState(wwin, NormalState, None); - */ -} - - -/* - *---------------------------------------------------------------------- - * wClientSetState-- - * Set the state of the client window to one of the window - * states defined in ICCCM (Iconic, Withdrawn, Normal) - * - * Side effects: - * The WM_STATE property of the window is updated as well as the - * WWindow.state variable. - *---------------------------------------------------------------------- - */ -void -wClientSetState(WWindow *wwin, int state, Window icon_win) -{ - CARD32 data[2]; - - wwin->state = state; - - data[0] = (unsigned long) state; - data[1] = (unsigned long) icon_win; - - XChangeProperty(dpy, wwin->client_win, _XA_WM_STATE, _XA_WM_STATE, 32, - PropModeReplace, (unsigned char *) data, 2); -} - - -void -wClientGetGravityOffsets(WWindow *wwin, int *ofs_x, int *ofs_y) -{ - switch (wwin->normal_hints->win_gravity) { - case ForgetGravity: - case CenterGravity: - case StaticGravity: - *ofs_x = 0; - *ofs_y = 0; - break; - case NorthWestGravity: - *ofs_x = -1; - *ofs_y = -1; - break; - case NorthGravity: - *ofs_x = 0; - *ofs_y = -1; - break; - case NorthEastGravity: - *ofs_x = 1; - *ofs_y = -1; - break; - case WestGravity: - *ofs_x = -1; - *ofs_y = 0; - break; - case EastGravity: - *ofs_x = 1; - *ofs_y = 0; - break; - case SouthWestGravity: - *ofs_x = -1; - *ofs_y = 1; - break; - case SouthGravity: - *ofs_x = 0; - *ofs_y = 1; - break; - case SouthEastGravity: - *ofs_x = 1; - *ofs_y = 1; - break; - } -} - - - -void -wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre) -{ - XWindowChanges xwc; - int nx, ny, nwidth, nheight; - int ofs_x, ofs_y; - - /* printf("configure event: %d %d %d %d\n", xcre->x, xcre->y, xcre->width, xcre->height);*/ - - if (wwin==NULL) { - /* - * configure a window that was not mapped by us - */ - xwc.x = xcre->x; - xwc.y = xcre->y; - xwc.width = xcre->width; - xwc.height = xcre->height; - xwc.border_width = xcre->border_width; - xwc.stack_mode = xcre->detail; - xwc.sibling = xcre->above; - XConfigureWindow(dpy, xcre->window, xcre->value_mask, &xwc); - return; - } -#ifdef SHAPE - if (wShapeSupported) { - int junk; - unsigned int ujunk; - int b_shaped; - - XShapeSelectInput(dpy, wwin->client_win, ShapeNotifyMask); - XShapeQueryExtents(dpy, wwin->client_win, &b_shaped, &junk, &junk, - &ujunk, &ujunk, &junk, &junk, &junk, &ujunk, - &ujunk); - wwin->flags.shaped = b_shaped; - } -#endif - if (xcre->value_mask & CWStackMode) { - WObjDescriptor *desc; - WWindow *sibling; - - if ((xcre->value_mask & CWSibling) && - (XFindContext(dpy, xcre->above, wWinContext, - (XPointer *)&desc) == XCSUCCESS) - && (desc->parent_type==WCLASS_WINDOW)) { - sibling=desc->parent; - xwc.sibling = sibling->frame->core->window; - } else { - xwc.sibling = xcre->above; - } - xwc.stack_mode = xcre->detail; - XConfigureWindow(dpy, wwin->frame->core->window, - xcre->value_mask & (CWSibling | CWStackMode), &xwc); - /* fix stacking order */ - RemakeStackList(wwin->screen_ptr); - } - - wClientGetGravityOffsets(wwin, &ofs_x, &ofs_y); - - if (xcre->value_mask & CWBorderWidth) { - wwin->old_border_width = xcre->border_width; - } - - if (!wwin->flags.shaded) { - /* If the window is shaded, wrong height will be set for the window */ - if (xcre->value_mask & CWX) { - nx = xcre->x; - /* Subtracting the border makes the window shift by 1 pixel -Dan */ - /*if (HAS_BORDER(wwin)) { - nx -= FRAME_BORDER_WIDTH; - }*/ - } else { - nx = wwin->frame_x; - } - - if (xcre->value_mask & CWY) { - ny = xcre->y - ((ofs_y < 0) ? 0 : wwin->frame->top_width); - /* Subtracting the border makes the window shift by 1 pixel -Dan */ - /*if (HAS_BORDER(wwin)) { - ny -= FRAME_BORDER_WIDTH; - }*/ - } else { - ny = wwin->frame_y; - } - - if (xcre->value_mask & CWWidth) - nwidth = xcre->width; - else - nwidth = wwin->frame->core->width; - - if (xcre->value_mask & CWHeight) - nheight = xcre->height; - else - nheight = wwin->frame->core->height - wwin->frame->top_width - wwin->frame->bottom_width; - - wWindowConfigure(wwin, nx, ny, nwidth, nheight); - wwin->old_geometry.x = nx; - wwin->old_geometry.y = ny; - wwin->old_geometry.width = nwidth; - wwin->old_geometry.height = nheight; - } -} - - -void -wClientSendProtocol(WWindow *wwin, Atom protocol, Time time) -{ - XEvent event; - - event.xclient.type = ClientMessage; - event.xclient.message_type = _XA_WM_PROTOCOLS; - event.xclient.format = 32; - event.xclient.display = dpy; - event.xclient.window = wwin->client_win; - event.xclient.data.l[0] = protocol; - event.xclient.data.l[1] = time; - event.xclient.data.l[2] = 0; - event.xclient.data.l[3] = 0; - XSendEvent(dpy, wwin->client_win, False, NoEventMask, &event); - XSync(dpy, False); -} - - - -void -wClientKill(WWindow *wwin) -{ - XKillClient(dpy, wwin->client_win); - - XFlush(dpy); -} - - - -/* - *---------------------------------------------------------------------- - * wClientCheckProperty-- - * Handles PropertyNotify'es, verifying which property was - * changed and updating internal state according to that, like redrawing - * the icon title when it is changed. - * - * Side effects: - * Depends on the changed property. - * - * TODO: _GNUSTEP_WM_ATTR - *---------------------------------------------------------------------- - */ -void -wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) -{ - XWindowAttributes attribs; - XWMHints *new_hints; - int i, g1, g2; - char *tmp = NULL; - - switch (event->atom) { - case XA_WM_NAME: - if (!wwin->flags.net_has_title) - { - /* window title was changed */ - if (!wFetchName(dpy, wwin->client_win, &tmp)) { - wWindowUpdateName(wwin, NULL); - } else { - wWindowUpdateName(wwin, tmp); - } - if (tmp) - XFree(tmp); - } - break; - - case XA_WM_ICON_NAME: - if (!wwin->flags.net_has_icon_title) - { - if (!wwin->icon) - break; - else { - char *new_title; - - /* icon title was changed */ - wGetIconName(dpy, wwin->client_win, &new_title); - wIconChangeTitle(wwin->icon, new_title); - } - } - break; - - case XA_WM_COMMAND: - if (wwin->main_window!=None) { - WApplication *wapp = wApplicationOf(wwin->main_window); - char *command; - - if (!wapp || !wapp->app_icon || wapp->app_icon->docked) - break; - - command = GetCommandForWindow(wwin->main_window); - if (command) { - if (wapp->app_icon->command) - wfree(wapp->app_icon->command); - wapp->app_icon->command = command; - } - } - break; - - case XA_WM_HINTS: - /* WM_HINTS */ - - new_hints = XGetWMHints(dpy, wwin->client_win); - - /* group leader update - * - * This means that the window is setting the leader after - * it was mapped, changing leaders or removing the leader. - * - * Valid state transitions are: - * - * _1 __2 - * / \ / \ - * v | v | - * (GC) (GC') - * / ^ / ^ - * 3| |4 5| |6 - * | | | | - * v / v / - * (G'C) (G'C') - * - * Where G is the window_group hint, C is CLIENT_LEADER property - * and ' indicates the hint is unset. - * - * 1,2 - change group leader to new value of window_group - * 3 - change leader to value of CLIENT_LEADER - * 4 - change leader to value of window_group - * 5 - destroy application - * 6 - create application - */ - if (new_hints && (new_hints->flags & WindowGroupHint) - && new_hints->window_group!=None) { - g2 = 1; - } else { - g2 = 0; - } - if (wwin->wm_hints && (wwin->wm_hints->flags & WindowGroupHint) - && wwin->wm_hints->window_group!=None) { - g1 = 1; - } else { - g1 = 0; - } - - if (wwin->client_leader) { - if (g1 && g2 - && wwin->wm_hints->window_group!=new_hints->window_group) { - i = 1; - } else if (g1 && !g2) { - i = 3; - } else if (!g1 && g2) { - i = 4; - } else { - i = 0; - } - } else { - if (g1 && g2 - && wwin->wm_hints->window_group!=new_hints->window_group) { - i = 2; - } else if (g1 && !g2) { - i = 5; - } else if (!g1 && g2) { - i = 6; - } else { - i = 0; - } - } - - /* Handling this may require more work. -Dan */ - if (wwin->fake_group!=NULL) { - i = 7; - } - - if (wwin->wm_hints) - XFree(wwin->wm_hints); - - wwin->wm_hints = new_hints; - - /* do action according to state transition */ - switch (i) { - /* 3 - change leader to value of CLIENT_LEADER */ - case 3: - wApplicationDestroy(wApplicationOf(wwin->main_window)); - wwin->main_window = wwin->client_leader; - wwin->group_id = None; - wApplicationCreate(wwin); - break; - - /* 1,2,4 - change leader to new value of window_group */ - case 1: - case 2: - case 4: - wApplicationDestroy(wApplicationOf(wwin->main_window)); - wwin->main_window = new_hints->window_group; - wwin->group_id = wwin->main_window; - wApplicationCreate(wwin); - break; - - /* 5 - destroy application */ - case 5: - wApplicationDestroy(wApplicationOf(wwin->main_window)); - wwin->main_window = None; - wwin->group_id = None; - break; - - /* 6 - create application */ - case 6: - wwin->main_window = new_hints->window_group; - wwin->group_id = wwin->main_window; - wApplicationCreate(wwin); - break; - /* 7 - we have a fake window group id, so just ignore anything else */ - case 7: - break; - } -#ifdef DEBUG - if (i) { - printf("window leader update caused state transition %i\n",i); - } -#endif - - if (wwin->wm_hints) { - /* update icon */ - if ((wwin->wm_hints->flags & IconPixmapHint) - || (wwin->wm_hints->flags & IconWindowHint)) { - WApplication *wapp; - - if (wwin->flags.miniaturized && wwin->icon) { - wIconUpdate(wwin->icon); - } - wapp = wApplicationOf(wwin->main_window); - if (wapp && wapp->app_icon) { - wIconUpdate(wapp->app_icon->icon); - } - } - - if (wwin->wm_hints->flags & UrgencyHint) - wwin->flags.urgent = 1; - else - wwin->flags.urgent = 0; - /*} else if (wwin->fake_group!=NULL) { - wwin->group_id = wwin->fake_group->leader;*/ - } else { - wwin->group_id = None; - } - break; - - case XA_WM_NORMAL_HINTS: - /* normal (geometry) hints */ - { - int foo; - unsigned bar; - - XGetWindowAttributes(dpy, wwin->client_win, &attribs); - wClientGetNormalHints(wwin, &attribs, False, &foo, &foo, - &bar, &bar); - /* TODO: should we check for consistency of the current - * size against the new geometry hints? */ - } - break; - - case XA_WM_TRANSIENT_FOR: - { - Window new_owner; - WWindow *owner; - - if (!XGetTransientForHint(dpy, wwin->client_win, &new_owner)) { - new_owner = None; - } else { - if (new_owner==0 || new_owner == wwin->client_win) { - new_owner = wwin->screen_ptr->root_win; - } - } - if (new_owner!=wwin->transient_for) { - owner = wWindowFor(wwin->transient_for); - if (owner) { - if (owner->flags.semi_focused) { - owner->flags.semi_focused = 0; - if ((owner->flags.mapped || owner->flags.shaded) - && owner->frame) - wFrameWindowPaint(owner->frame); - } - } - owner = wWindowFor(new_owner); - if (owner) { - if (!owner->flags.semi_focused) { - owner->flags.semi_focused = 1; - if ((owner->flags.mapped || owner->flags.shaded) - && owner->frame) - wFrameWindowPaint(owner->frame); - } - } - wwin->transient_for = new_owner; - if (new_owner==None) { - if (WFLAGP(wwin, no_miniaturizable)) { - WSETUFLAG(wwin, no_miniaturizable, 0); - WSETUFLAG(wwin, no_miniaturize_button, 0); - if (wwin->frame) - wWindowConfigureBorders(wwin); - } - } else if (!WFLAGP(wwin, no_miniaturizable)) { - WSETUFLAG(wwin, no_miniaturizable, 1); - WSETUFLAG(wwin, no_miniaturize_button, 1); - if (wwin->frame) - wWindowConfigureBorders(wwin); - } - } - } - break; - - default: - if (event->atom==_XA_WM_PROTOCOLS) { - - PropGetProtocols(wwin->client_win, &wwin->protocols); - - WSETUFLAG(wwin, kill_close, !wwin->protocols.DELETE_WINDOW); - - if (wwin->frame) - wWindowUpdateButtonImages(wwin); - - } else if (event->atom==_XA_WM_COLORMAP_WINDOWS) { - - GetColormapWindows(wwin); - wColormapInstallForWindow(wwin->screen_ptr, wwin); - - } else if (event->atom==_XA_WINDOWMAKER_MENU) { - WApplication *wapp; - - wapp = wApplicationOf(wwin->main_window); - if (wapp) { - if (wapp->menu) { - /* update menu */ - /* TODO: remake appmenu update */ - wAppMenuDestroy(wapp->menu); - } - if (wwin->fake_group) { - extern WPreferences wPreferences; - WScreen *scr = wwin->screen_ptr; - WWindow *foo = scr->focused_window; - WFakeGroupLeader *fPtr = wwin->fake_group; - - wApplicationDestroy(wapp); - while (foo) { - if (foo->fake_group && foo->fake_group==fPtr) { - WSETUFLAG(foo, shared_appicon, 0); - foo->fake_group = NULL; - if (foo->group_id!=None) - foo->main_window = foo->group_id; - else if (foo->client_leader!=None) - foo->main_window = foo->client_leader; - else if (WFLAGP(foo, emulate_appicon)) - foo->main_window = foo->client_win; - else - foo->main_window = None; - if (foo->main_window) { - wapp = wApplicationCreate(foo); - } - } - foo = foo->prev; - } - - if (fPtr->leader!=None) - XDestroyWindow(dpy, fPtr->leader); - fPtr->retainCount = 0; - fPtr->leader = None; - fPtr->origLeader = None; - - wapp = wApplicationOf(wwin->main_window); - if (wapp) { - wapp->menu = wAppMenuGet(scr, wwin->main_window); - } - if (wPreferences.auto_arrange_icons) { - wArrangeIcons(wwin->screen_ptr, True); - } - } else { - wapp->menu = wAppMenuGet(wwin->screen_ptr, wwin->main_window); - } - /* make the appmenu be mapped */ - wSetFocusTo(wwin->screen_ptr, NULL); - wSetFocusTo(wwin->screen_ptr, wwin->screen_ptr->focused_window); - } - } else if (event->atom==_XA_GNUSTEP_WM_ATTR) { - GNUstepWMAttributes *attr; - - PropGetGNUstepWMAttr(wwin->client_win, &attr); - - wWindowUpdateGNUstepAttr(wwin, attr); - - XFree(attr); - } else { -#ifdef NETWM_HINTS - wNETWMCheckClientHintChange(wwin, event); -#endif - } - } -} - - -/* - *---------------------------------------------------------------------- - * wClientGetNormalHints-- - * Get size (normal) hints and a default geometry for the client - * window. The hints are also checked for inconsistency. If geometry is - * True, the returned data will account for client specified initial - * geometry. - * - * Side effects: - * normal_hints is filled with valid data. - *---------------------------------------------------------------------- - */ -void -wClientGetNormalHints(WWindow *wwin, XWindowAttributes *wattribs, Bool geometry, - int *x, int *y, unsigned *width, unsigned *height) -{ - int pre_icccm = 0; /* not used */ - - /* find a position for the window */ - if (!wwin->normal_hints) - wwin->normal_hints = XAllocSizeHints(); - - if (!PropGetNormalHints(wwin->client_win, wwin->normal_hints, &pre_icccm)) { - wwin->normal_hints->flags = 0; - } - *x = wattribs->x; - *y = wattribs->y; - - *width = wattribs->width; - *height = wattribs->height; - - if (!(wwin->normal_hints->flags & PWinGravity)) { - wwin->normal_hints->win_gravity = NorthWestGravity; - } - if (!(wwin->normal_hints->flags & PMinSize)) { - wwin->normal_hints->min_width = MIN_WINDOW_SIZE; - wwin->normal_hints->min_height = MIN_WINDOW_SIZE; - } - if (!(wwin->normal_hints->flags & PBaseSize)) { - wwin->normal_hints->base_width = 0; - wwin->normal_hints->base_height = 0; - } - if (!(wwin->normal_hints->flags & PMaxSize)) { - wwin->normal_hints->max_width = wwin->screen_ptr->scr_width*2; - wwin->normal_hints->max_height = wwin->screen_ptr->scr_height*2; - } - - /* some buggy apps set weird hints.. */ - if (wwin->normal_hints->min_width <= 0) - wwin->normal_hints->min_width = MIN_WINDOW_SIZE; - - if (wwin->normal_hints->min_height <= 0) - wwin->normal_hints->min_height = MIN_WINDOW_SIZE; - - - if (wwin->normal_hints->max_width < wwin->normal_hints->min_width) - wwin->normal_hints->max_width = wwin->normal_hints->min_width; - - if (wwin->normal_hints->max_height < wwin->normal_hints->min_height) - wwin->normal_hints->max_height = wwin->normal_hints->min_height; - - if (!(wwin->normal_hints->flags & PResizeInc)) { - wwin->normal_hints->width_inc = 1; - wwin->normal_hints->height_inc = 1; - } else { - if (wwin->normal_hints->width_inc <= 0) - wwin->normal_hints->width_inc = 1; - if (wwin->normal_hints->height_inc <= 0) - wwin->normal_hints->height_inc = 1; - } - - if (wwin->normal_hints->flags & PAspect) { - if (wwin->normal_hints->min_aspect.x < 1) - wwin->normal_hints->min_aspect.x = 1; - if (wwin->normal_hints->min_aspect.y < 1) - wwin->normal_hints->min_aspect.y = 1; - - if (wwin->normal_hints->max_aspect.x < 1) - wwin->normal_hints->max_aspect.x = 1; - if (wwin->normal_hints->max_aspect.y < 1) - wwin->normal_hints->max_aspect.y = 1; - } - - if (wwin->normal_hints->min_height > wwin->normal_hints->max_height) { - wwin->normal_hints->min_height = wwin->normal_hints->max_height; - } - if (wwin->normal_hints->min_width > wwin->normal_hints->max_width) { - wwin->normal_hints->min_width = wwin->normal_hints->max_width; - } - -#ifdef IGNORE_PPOSITION - wwin->normal_hints->flags &= ~PPosition; -#endif - - if (pre_icccm && !wwin->screen_ptr->flags.startup && geometry) { - if (wwin->normal_hints->flags & (USPosition|PPosition)) { - *x = wwin->normal_hints->x; - *y = wwin->normal_hints->y; - } - if (wwin->normal_hints->flags & (USSize|PSize)) { - *width = wwin->normal_hints->width; - *height = wwin->normal_hints->height; - } - } -} - - -void -GetColormapWindows(WWindow *wwin) -{ -#ifndef NO_CRASHES - if (wwin->cmap_windows) { - XFree(wwin->cmap_windows); - } - - wwin->cmap_windows = NULL; - wwin->cmap_window_no = 0; - - if (!XGetWMColormapWindows(dpy, wwin->client_win, &(wwin->cmap_windows), - &(wwin->cmap_window_no)) - || !wwin->cmap_windows) { - wwin->cmap_window_no = 0; - wwin->cmap_windows = NULL; - } - -#endif -} +/* + * Window Maker window manager + * + * Copyright (c) 1997-2003 Alfredo K. Kojima + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#include "wconfig.h" + +#include +#include +#include +#ifdef SHAPE +#include +#endif + +#include +#include +#include + +#include "WindowMaker.h" +#include "wcore.h" +#include "framewin.h" +#include "window.h" +#include "properties.h" +#include "actions.h" +#include "icon.h" +#include "client.h" +#include "funcs.h" +#include "stacking.h" +#include "appicon.h" +#include "appmenu.h" +#ifdef NETWM_HINTS +# include "wmspec.h" +#endif + +/****** Global Variables ******/ + +/* contexts */ +extern XContext wWinContext; + +extern Atom _XA_WM_STATE; +extern Atom _XA_WM_PROTOCOLS; +extern Atom _XA_WM_COLORMAP_WINDOWS; + +extern Atom _XA_WINDOWMAKER_MENU; + +extern Atom _XA_GNUSTEP_WM_ATTR; +extern Atom _XA_GNUSTEP_WM_RESIZEBAR; + +#ifdef SHAPE +extern Bool wShapeSupported; +#endif + +/* + *-------------------------------------------------------------------- + * wClientRestore-- + * Reparent the window back to the root window. + * + *-------------------------------------------------------------------- + */ +void wClientRestore(WWindow * wwin) +{ +#if 0 + int gx, gy; + + wClientGetGravityOffsets(wwin, &gx, &gy); + /* set the positio of the frame on screen */ + wwin->frame_x -= gx * FRAME_BORDER_WIDTH; + wwin->frame_y -= gy * FRAME_BORDER_WIDTH; + /* if gravity is to the south, account for the border sizes */ + if (gy > 0) + wwin->frame_y += (wwin->frame->top_width + wwin->frame->bottom_width); +#endif + XSetWindowBorderWidth(dpy, wwin->client_win, wwin->old_border_width); + XReparentWindow(dpy, wwin->client_win, wwin->screen_ptr->root_win, wwin->frame_x, wwin->frame_y); + + /* don't let the window get iconified after restart */ + /* + if (wwin->flags.shaded) + wClientSetState(wwin, NormalState, None); + */ +} + +/* + *---------------------------------------------------------------------- + * wClientSetState-- + * Set the state of the client window to one of the window + * states defined in ICCCM (Iconic, Withdrawn, Normal) + * + * Side effects: + * The WM_STATE property of the window is updated as well as the + * WWindow.state variable. + *---------------------------------------------------------------------- + */ +void wClientSetState(WWindow * wwin, int state, Window icon_win) +{ + CARD32 data[2]; + + wwin->state = state; + + data[0] = (unsigned long)state; + data[1] = (unsigned long)icon_win; + + XChangeProperty(dpy, wwin->client_win, _XA_WM_STATE, _XA_WM_STATE, 32, + PropModeReplace, (unsigned char *)data, 2); +} + +void wClientGetGravityOffsets(WWindow * wwin, int *ofs_x, int *ofs_y) +{ + switch (wwin->normal_hints->win_gravity) { + case ForgetGravity: + case CenterGravity: + case StaticGravity: + *ofs_x = 0; + *ofs_y = 0; + break; + case NorthWestGravity: + *ofs_x = -1; + *ofs_y = -1; + break; + case NorthGravity: + *ofs_x = 0; + *ofs_y = -1; + break; + case NorthEastGravity: + *ofs_x = 1; + *ofs_y = -1; + break; + case WestGravity: + *ofs_x = -1; + *ofs_y = 0; + break; + case EastGravity: + *ofs_x = 1; + *ofs_y = 0; + break; + case SouthWestGravity: + *ofs_x = -1; + *ofs_y = 1; + break; + case SouthGravity: + *ofs_x = 0; + *ofs_y = 1; + break; + case SouthEastGravity: + *ofs_x = 1; + *ofs_y = 1; + break; + } +} + +void wClientConfigure(WWindow * wwin, XConfigureRequestEvent * xcre) +{ + XWindowChanges xwc; + int nx, ny, nwidth, nheight; + int ofs_x, ofs_y; + + /* printf("configure event: %d %d %d %d\n", xcre->x, xcre->y, xcre->width, xcre->height); */ + + if (wwin == NULL) { + /* + * configure a window that was not mapped by us + */ + xwc.x = xcre->x; + xwc.y = xcre->y; + xwc.width = xcre->width; + xwc.height = xcre->height; + xwc.border_width = xcre->border_width; + xwc.stack_mode = xcre->detail; + xwc.sibling = xcre->above; + XConfigureWindow(dpy, xcre->window, xcre->value_mask, &xwc); + return; + } +#ifdef SHAPE + if (wShapeSupported) { + int junk; + unsigned int ujunk; + int b_shaped; + + XShapeSelectInput(dpy, wwin->client_win, ShapeNotifyMask); + XShapeQueryExtents(dpy, wwin->client_win, &b_shaped, &junk, &junk, + &ujunk, &ujunk, &junk, &junk, &junk, &ujunk, &ujunk); + wwin->flags.shaped = b_shaped; + } +#endif + if (xcre->value_mask & CWStackMode) { + WObjDescriptor *desc; + WWindow *sibling; + + if ((xcre->value_mask & CWSibling) && + (XFindContext(dpy, xcre->above, wWinContext, (XPointer *) & desc) == XCSUCCESS) + && (desc->parent_type == WCLASS_WINDOW)) { + sibling = desc->parent; + xwc.sibling = sibling->frame->core->window; + } else { + xwc.sibling = xcre->above; + } + xwc.stack_mode = xcre->detail; + XConfigureWindow(dpy, wwin->frame->core->window, + xcre->value_mask & (CWSibling | CWStackMode), &xwc); + /* fix stacking order */ + RemakeStackList(wwin->screen_ptr); + } + + wClientGetGravityOffsets(wwin, &ofs_x, &ofs_y); + + if (xcre->value_mask & CWBorderWidth) { + wwin->old_border_width = xcre->border_width; + } + + if (!wwin->flags.shaded) { + /* If the window is shaded, wrong height will be set for the window */ + if (xcre->value_mask & CWX) { + nx = xcre->x; + /* Subtracting the border makes the window shift by 1 pixel -Dan */ + /*if (HAS_BORDER(wwin)) { + nx -= FRAME_BORDER_WIDTH; + } */ + } else { + nx = wwin->frame_x; + } + + if (xcre->value_mask & CWY) { + ny = xcre->y - ((ofs_y < 0) ? 0 : wwin->frame->top_width); + /* Subtracting the border makes the window shift by 1 pixel -Dan */ + /*if (HAS_BORDER(wwin)) { + ny -= FRAME_BORDER_WIDTH; + } */ + } else { + ny = wwin->frame_y; + } + + if (xcre->value_mask & CWWidth) + nwidth = xcre->width; + else + nwidth = wwin->frame->core->width; + + if (xcre->value_mask & CWHeight) + nheight = xcre->height; + else + nheight = wwin->frame->core->height - wwin->frame->top_width - wwin->frame->bottom_width; + + wWindowConfigure(wwin, nx, ny, nwidth, nheight); + wwin->old_geometry.x = nx; + wwin->old_geometry.y = ny; + wwin->old_geometry.width = nwidth; + wwin->old_geometry.height = nheight; + } +} + +void wClientSendProtocol(WWindow * wwin, Atom protocol, Time time) +{ + XEvent event; + + event.xclient.type = ClientMessage; + event.xclient.message_type = _XA_WM_PROTOCOLS; + event.xclient.format = 32; + event.xclient.display = dpy; + event.xclient.window = wwin->client_win; + event.xclient.data.l[0] = protocol; + event.xclient.data.l[1] = time; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 0; + XSendEvent(dpy, wwin->client_win, False, NoEventMask, &event); + XSync(dpy, False); +} + +void wClientKill(WWindow * wwin) +{ + XKillClient(dpy, wwin->client_win); + + XFlush(dpy); +} + +/* + *---------------------------------------------------------------------- + * wClientCheckProperty-- + * Handles PropertyNotify'es, verifying which property was + * changed and updating internal state according to that, like redrawing + * the icon title when it is changed. + * + * Side effects: + * Depends on the changed property. + * + * TODO: _GNUSTEP_WM_ATTR + *---------------------------------------------------------------------- + */ +void wClientCheckProperty(WWindow * wwin, XPropertyEvent * event) +{ + XWindowAttributes attribs; + XWMHints *new_hints; + int i, g1, g2; + char *tmp = NULL; + + switch (event->atom) { + case XA_WM_NAME: + if (!wwin->flags.net_has_title) { + /* window title was changed */ + if (!wFetchName(dpy, wwin->client_win, &tmp)) { + wWindowUpdateName(wwin, NULL); + } else { + wWindowUpdateName(wwin, tmp); + } + if (tmp) + XFree(tmp); + } + break; + + case XA_WM_ICON_NAME: + if (!wwin->flags.net_has_icon_title) { + if (!wwin->icon) + break; + else { + char *new_title; + + /* icon title was changed */ + wGetIconName(dpy, wwin->client_win, &new_title); + wIconChangeTitle(wwin->icon, new_title); + } + } + break; + + case XA_WM_COMMAND: + if (wwin->main_window != None) { + WApplication *wapp = wApplicationOf(wwin->main_window); + char *command; + + if (!wapp || !wapp->app_icon || wapp->app_icon->docked) + break; + + command = GetCommandForWindow(wwin->main_window); + if (command) { + if (wapp->app_icon->command) + wfree(wapp->app_icon->command); + wapp->app_icon->command = command; + } + } + break; + + case XA_WM_HINTS: + /* WM_HINTS */ + + new_hints = XGetWMHints(dpy, wwin->client_win); + + /* group leader update + * + * This means that the window is setting the leader after + * it was mapped, changing leaders or removing the leader. + * + * Valid state transitions are: + * + * _1 __2 + * / \ / \ + * v | v | + * (GC) (GC') + * / ^ / ^ + * 3| |4 5| |6 + * | | | | + * v / v / + * (G'C) (G'C') + * + * Where G is the window_group hint, C is CLIENT_LEADER property + * and ' indicates the hint is unset. + * + * 1,2 - change group leader to new value of window_group + * 3 - change leader to value of CLIENT_LEADER + * 4 - change leader to value of window_group + * 5 - destroy application + * 6 - create application + */ + if (new_hints && (new_hints->flags & WindowGroupHint) + && new_hints->window_group != None) { + g2 = 1; + } else { + g2 = 0; + } + if (wwin->wm_hints && (wwin->wm_hints->flags & WindowGroupHint) + && wwin->wm_hints->window_group != None) { + g1 = 1; + } else { + g1 = 0; + } + + if (wwin->client_leader) { + if (g1 && g2 && wwin->wm_hints->window_group != new_hints->window_group) { + i = 1; + } else if (g1 && !g2) { + i = 3; + } else if (!g1 && g2) { + i = 4; + } else { + i = 0; + } + } else { + if (g1 && g2 && wwin->wm_hints->window_group != new_hints->window_group) { + i = 2; + } else if (g1 && !g2) { + i = 5; + } else if (!g1 && g2) { + i = 6; + } else { + i = 0; + } + } + + /* Handling this may require more work. -Dan */ + if (wwin->fake_group != NULL) { + i = 7; + } + + if (wwin->wm_hints) + XFree(wwin->wm_hints); + + wwin->wm_hints = new_hints; + + /* do action according to state transition */ + switch (i) { + /* 3 - change leader to value of CLIENT_LEADER */ + case 3: + wApplicationDestroy(wApplicationOf(wwin->main_window)); + wwin->main_window = wwin->client_leader; + wwin->group_id = None; + wApplicationCreate(wwin); + break; + + /* 1,2,4 - change leader to new value of window_group */ + case 1: + case 2: + case 4: + wApplicationDestroy(wApplicationOf(wwin->main_window)); + wwin->main_window = new_hints->window_group; + wwin->group_id = wwin->main_window; + wApplicationCreate(wwin); + break; + + /* 5 - destroy application */ + case 5: + wApplicationDestroy(wApplicationOf(wwin->main_window)); + wwin->main_window = None; + wwin->group_id = None; + break; + + /* 6 - create application */ + case 6: + wwin->main_window = new_hints->window_group; + wwin->group_id = wwin->main_window; + wApplicationCreate(wwin); + break; + /* 7 - we have a fake window group id, so just ignore anything else */ + case 7: + break; + } +#ifdef DEBUG + if (i) { + printf("window leader update caused state transition %i\n", i); + } +#endif + + if (wwin->wm_hints) { + /* update icon */ + if ((wwin->wm_hints->flags & IconPixmapHint) + || (wwin->wm_hints->flags & IconWindowHint)) { + WApplication *wapp; + + if (wwin->flags.miniaturized && wwin->icon) { + wIconUpdate(wwin->icon); + } + wapp = wApplicationOf(wwin->main_window); + if (wapp && wapp->app_icon) { + wIconUpdate(wapp->app_icon->icon); + } + } + + if (wwin->wm_hints->flags & UrgencyHint) + wwin->flags.urgent = 1; + else + wwin->flags.urgent = 0; + /*} else if (wwin->fake_group!=NULL) { + wwin->group_id = wwin->fake_group->leader; */ + } else { + wwin->group_id = None; + } + break; + + case XA_WM_NORMAL_HINTS: + /* normal (geometry) hints */ + { + int foo; + unsigned bar; + + XGetWindowAttributes(dpy, wwin->client_win, &attribs); + wClientGetNormalHints(wwin, &attribs, False, &foo, &foo, &bar, &bar); + /* TODO: should we check for consistency of the current + * size against the new geometry hints? */ + } + break; + + case XA_WM_TRANSIENT_FOR: + { + Window new_owner; + WWindow *owner; + + if (!XGetTransientForHint(dpy, wwin->client_win, &new_owner)) { + new_owner = None; + } else { + if (new_owner == 0 || new_owner == wwin->client_win) { + new_owner = wwin->screen_ptr->root_win; + } + } + if (new_owner != wwin->transient_for) { + owner = wWindowFor(wwin->transient_for); + if (owner) { + if (owner->flags.semi_focused) { + owner->flags.semi_focused = 0; + if ((owner->flags.mapped || owner->flags.shaded) + && owner->frame) + wFrameWindowPaint(owner->frame); + } + } + owner = wWindowFor(new_owner); + if (owner) { + if (!owner->flags.semi_focused) { + owner->flags.semi_focused = 1; + if ((owner->flags.mapped || owner->flags.shaded) + && owner->frame) + wFrameWindowPaint(owner->frame); + } + } + wwin->transient_for = new_owner; + if (new_owner == None) { + if (WFLAGP(wwin, no_miniaturizable)) { + WSETUFLAG(wwin, no_miniaturizable, 0); + WSETUFLAG(wwin, no_miniaturize_button, 0); + if (wwin->frame) + wWindowConfigureBorders(wwin); + } + } else if (!WFLAGP(wwin, no_miniaturizable)) { + WSETUFLAG(wwin, no_miniaturizable, 1); + WSETUFLAG(wwin, no_miniaturize_button, 1); + if (wwin->frame) + wWindowConfigureBorders(wwin); + } + } + } + break; + + default: + if (event->atom == _XA_WM_PROTOCOLS) { + + PropGetProtocols(wwin->client_win, &wwin->protocols); + + WSETUFLAG(wwin, kill_close, !wwin->protocols.DELETE_WINDOW); + + if (wwin->frame) + wWindowUpdateButtonImages(wwin); + + } else if (event->atom == _XA_WM_COLORMAP_WINDOWS) { + + GetColormapWindows(wwin); + wColormapInstallForWindow(wwin->screen_ptr, wwin); + + } else if (event->atom == _XA_WINDOWMAKER_MENU) { + WApplication *wapp; + + wapp = wApplicationOf(wwin->main_window); + if (wapp) { + if (wapp->menu) { + /* update menu */ + /* TODO: remake appmenu update */ + wAppMenuDestroy(wapp->menu); + } + if (wwin->fake_group) { + extern WPreferences wPreferences; + WScreen *scr = wwin->screen_ptr; + WWindow *foo = scr->focused_window; + WFakeGroupLeader *fPtr = wwin->fake_group; + + wApplicationDestroy(wapp); + while (foo) { + if (foo->fake_group && foo->fake_group == fPtr) { + WSETUFLAG(foo, shared_appicon, 0); + foo->fake_group = NULL; + if (foo->group_id != None) + foo->main_window = foo->group_id; + else if (foo->client_leader != None) + foo->main_window = foo->client_leader; + else if (WFLAGP(foo, emulate_appicon)) + foo->main_window = foo->client_win; + else + foo->main_window = None; + if (foo->main_window) { + wapp = wApplicationCreate(foo); + } + } + foo = foo->prev; + } + + if (fPtr->leader != None) + XDestroyWindow(dpy, fPtr->leader); + fPtr->retainCount = 0; + fPtr->leader = None; + fPtr->origLeader = None; + + wapp = wApplicationOf(wwin->main_window); + if (wapp) { + wapp->menu = wAppMenuGet(scr, wwin->main_window); + } + if (wPreferences.auto_arrange_icons) { + wArrangeIcons(wwin->screen_ptr, True); + } + } else { + wapp->menu = wAppMenuGet(wwin->screen_ptr, wwin->main_window); + } + /* make the appmenu be mapped */ + wSetFocusTo(wwin->screen_ptr, NULL); + wSetFocusTo(wwin->screen_ptr, wwin->screen_ptr->focused_window); + } + } else if (event->atom == _XA_GNUSTEP_WM_ATTR) { + GNUstepWMAttributes *attr; + + PropGetGNUstepWMAttr(wwin->client_win, &attr); + + wWindowUpdateGNUstepAttr(wwin, attr); + + XFree(attr); + } else { +#ifdef NETWM_HINTS + wNETWMCheckClientHintChange(wwin, event); +#endif + } + } +} + +/* + *---------------------------------------------------------------------- + * wClientGetNormalHints-- + * Get size (normal) hints and a default geometry for the client + * window. The hints are also checked for inconsistency. If geometry is + * True, the returned data will account for client specified initial + * geometry. + * + * Side effects: + * normal_hints is filled with valid data. + *---------------------------------------------------------------------- + */ +void +wClientGetNormalHints(WWindow * wwin, XWindowAttributes * wattribs, Bool geometry, + int *x, int *y, unsigned *width, unsigned *height) +{ + int pre_icccm = 0; /* not used */ + + /* find a position for the window */ + if (!wwin->normal_hints) + wwin->normal_hints = XAllocSizeHints(); + + if (!PropGetNormalHints(wwin->client_win, wwin->normal_hints, &pre_icccm)) { + wwin->normal_hints->flags = 0; + } + *x = wattribs->x; + *y = wattribs->y; + + *width = wattribs->width; + *height = wattribs->height; + + if (!(wwin->normal_hints->flags & PWinGravity)) { + wwin->normal_hints->win_gravity = NorthWestGravity; + } + if (!(wwin->normal_hints->flags & PMinSize)) { + wwin->normal_hints->min_width = MIN_WINDOW_SIZE; + wwin->normal_hints->min_height = MIN_WINDOW_SIZE; + } + if (!(wwin->normal_hints->flags & PBaseSize)) { + wwin->normal_hints->base_width = 0; + wwin->normal_hints->base_height = 0; + } + if (!(wwin->normal_hints->flags & PMaxSize)) { + wwin->normal_hints->max_width = wwin->screen_ptr->scr_width * 2; + wwin->normal_hints->max_height = wwin->screen_ptr->scr_height * 2; + } + + /* some buggy apps set weird hints.. */ + if (wwin->normal_hints->min_width <= 0) + wwin->normal_hints->min_width = MIN_WINDOW_SIZE; + + if (wwin->normal_hints->min_height <= 0) + wwin->normal_hints->min_height = MIN_WINDOW_SIZE; + + if (wwin->normal_hints->max_width < wwin->normal_hints->min_width) + wwin->normal_hints->max_width = wwin->normal_hints->min_width; + + if (wwin->normal_hints->max_height < wwin->normal_hints->min_height) + wwin->normal_hints->max_height = wwin->normal_hints->min_height; + + if (!(wwin->normal_hints->flags & PResizeInc)) { + wwin->normal_hints->width_inc = 1; + wwin->normal_hints->height_inc = 1; + } else { + if (wwin->normal_hints->width_inc <= 0) + wwin->normal_hints->width_inc = 1; + if (wwin->normal_hints->height_inc <= 0) + wwin->normal_hints->height_inc = 1; + } + + if (wwin->normal_hints->flags & PAspect) { + if (wwin->normal_hints->min_aspect.x < 1) + wwin->normal_hints->min_aspect.x = 1; + if (wwin->normal_hints->min_aspect.y < 1) + wwin->normal_hints->min_aspect.y = 1; + + if (wwin->normal_hints->max_aspect.x < 1) + wwin->normal_hints->max_aspect.x = 1; + if (wwin->normal_hints->max_aspect.y < 1) + wwin->normal_hints->max_aspect.y = 1; + } + + if (wwin->normal_hints->min_height > wwin->normal_hints->max_height) { + wwin->normal_hints->min_height = wwin->normal_hints->max_height; + } + if (wwin->normal_hints->min_width > wwin->normal_hints->max_width) { + wwin->normal_hints->min_width = wwin->normal_hints->max_width; + } +#ifdef IGNORE_PPOSITION + wwin->normal_hints->flags &= ~PPosition; +#endif + + if (pre_icccm && !wwin->screen_ptr->flags.startup && geometry) { + if (wwin->normal_hints->flags & (USPosition | PPosition)) { + *x = wwin->normal_hints->x; + *y = wwin->normal_hints->y; + } + if (wwin->normal_hints->flags & (USSize | PSize)) { + *width = wwin->normal_hints->width; + *height = wwin->normal_hints->height; + } + } +} + +void GetColormapWindows(WWindow * wwin) +{ +#ifndef NO_CRASHES + if (wwin->cmap_windows) { + XFree(wwin->cmap_windows); + } + + wwin->cmap_windows = NULL; + wwin->cmap_window_no = 0; + + if (!XGetWMColormapWindows(dpy, wwin->client_win, &(wwin->cmap_windows), &(wwin->cmap_window_no)) + || !wwin->cmap_windows) { + wwin->cmap_window_no = 0; + wwin->cmap_windows = NULL; + } +#endif +}