diff options
Diffstat (limited to 'matchbox/mb-wm-window-type-simple.c')
-rw-r--r-- | matchbox/mb-wm-window-type-simple.c | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/matchbox/mb-wm-window-type-simple.c b/matchbox/mb-wm-window-type-simple.c new file mode 100644 index 0000000..562ee17 --- /dev/null +++ b/matchbox/mb-wm-window-type-simple.c @@ -0,0 +1,742 @@ +/* + * Matchbox Window Manager II - A lightweight window manager not for the + * desktop. + * + * Authored By Matthew Allum <mallum@o-hand.com> + * + * Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com + * + * 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, 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. + * + */ + +#include "matchbox.h" +#include "mb-wm-theme.h" + +#include <X11/Xmd.h> + +#if ENABLE_COMPOSITE +#include <X11/extensions/Xrender.h> +#endif + +#ifdef HAVE_XEXT +#include <X11/extensions/shape.h> +#endif + +static void +mb_wm_window_type_simple_realize (MBWindowManagerClient *client); + +static void +mb_wm_window_type_simple_stack (MBWindowManagerClient *client, + int flags); +static void +mb_wm_window_type_simple_show (MBWindowManagerClient *client); + +static void +mb_wm_window_type_simple_hide (MBWindowManagerClient *client); + + +static void +mb_wm_window_type_simple_display_sync (MBWindowManagerClient *client); + +static Bool +mb_wm_window_type_simple_request_geometry (MBWindowManagerClient *client, + MBGeometry *new_geometry, + MBWMClientReqGeomType flags); + +static Bool +mb_wm_window_type_simple_focus (MBWindowManagerClient *client); + +static void +mb_wm_window_type_simple_class_init (MBWMObjectClass *klass) +{ + MBWindowManagerClientClass *client; + + MBWM_MARK(); + + client = (MBWindowManagerClientClass *)klass; + + client->realize = mb_wm_window_type_simple_realize; + client->geometry = mb_wm_window_type_simple_request_geometry; + client->stack = mb_wm_window_type_simple_stack; + client->show = mb_wm_window_type_simple_show; + client->hide = mb_wm_window_type_simple_hide; + client->sync = mb_wm_window_type_simple_display_sync; + client->focus = mb_wm_window_type_simple_focus; + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMWindowTypeSimple"; +#endif +} + +static void +mb_wm_window_type_simple_destroy (MBWMObject *this) +{ + MBWindowManagerClient *parent; + MBWindowManagerClient *client; + MBWMManager *wm; + + MBWM_MARK(); + + client = MB_WM_CLIENT(this); + + wm = client->wmref; + + mb_wm_util_trap_x_errors(); + + if (client->xwin_frame) + { + XReparentWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client), + wm->root_win->xwindow, 0, 0); + + XDestroyWindow (wm->xdpy, client->xwin_frame); + client->xwin_frame = None; + + + if (client->xwin_modal_blocker) + { + XDestroyWindow (wm->xdpy, client->xwin_modal_blocker); + client->xwin_modal_blocker = None; + } + } + + XSync(wm->xdpy, False); + mb_wm_util_untrap_x_errors(); + + parent = mb_wm_client_get_transient_for (MB_WM_CLIENT(this)); + + if (parent) + mb_wm_client_remove_transient (parent, MB_WM_CLIENT(this)); +} + +static int +mb_wm_window_type_simple_init (MBWMObject *this, va_list vap) +{ + return 1; +} + +int +mb_wm_window_type_simple_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMWindowTypeSimpleClass), + sizeof (MBWMWindowTypeSimple), + mb_wm_window_type_simple_init, + mb_wm_window_type_simple_destroy, + mb_wm_window_type_simple_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT, 0); + } + + return type; +} + +static void +mb_wm_window_type_simple_realize (MBWindowManagerClient *client) +{ + MBWMManager *wm = client->wmref; + + XSetWindowAttributes attr; + + MBWM_ASSERT(client->window != NULL); + + /* create the frame window */ + + attr.override_redirect = True; + attr.background_pixel = BlackPixel(wm->xdpy, wm->xscreen); + attr.event_mask = MBWMChildMask|MBWMButtonMask|ExposureMask; + + /* This should probably be called via rather than on new clien sync() ...? */ + /* + * We only create a frame window if the client is decorated (decors are + * constructed in the _init functions, so we can easily test if the frame + * is needed or not). + */ + if (client->decor) + { + if (client->xwin_frame == None) + { +#if ENABLE_COMPOSITE + if (mb_wm_client_is_argb32 (client)) + { + attr.colormap = client->window->colormap; + + client->xwin_frame + = XCreateWindow(wm->xdpy, wm->root_win->xwindow, + client->frame_geometry.x, + client->frame_geometry.y, + client->frame_geometry.width, + client->frame_geometry.height, + 0, + 32, + InputOutput, + client->window->visual, + CWOverrideRedirect|CWEventMask|CWBackPixel| + CWBorderPixel|CWColormap, + &attr); + } + else +#endif + { + client->xwin_frame + = XCreateWindow(wm->xdpy, wm->root_win->xwindow, + client->frame_geometry.x, + client->frame_geometry.y, + client->frame_geometry.width, + client->frame_geometry.height, + 0, + CopyFromParent, + CopyFromParent, + CopyFromParent, + CWOverrideRedirect|CWEventMask|CWBackPixel, + &attr); + } + + /* + * Assume geometry sync will fix this up correctly togeather with + * any decoration creation. Layout manager will call this + */ + XReparentWindow(wm->xdpy, + MB_WM_CLIENT_XWIN(client), + client->xwin_frame, + 0, 0); + } + else + { + /* + * This is an undecorated client; we Must reparent the window to our + * root, otherwise we restacking of pre-existing windows might fail. + */ + XReparentWindow(client->wmref->xdpy, MB_WM_CLIENT_XWIN(client), + client->wmref->root_win->xwindow, 0, 0); + } + + /* + * If this is a system-modal client and the global setting is to support + * system modal windows, we create a fullscreen, input-only window that + * gets stacked immediately bellow it, catching any input events that + * fall outside of the system-modal client. + */ + if (mb_wm_client_is_modal (client) && + !mb_wm_client_get_transient_for (client) && + mb_wm_manager_get_modality_type (wm) == MBWMModalitySystem) + { + XSetWindowAttributes attr; + attr.override_redirect = True; + attr.event_mask = MBWMChildMask|ButtonPressMask|ExposureMask; + + client->xwin_modal_blocker = + XCreateWindow (wm->xdpy, + wm->root_win->xwindow, + 0, 0, + wm->xdpy_width, + wm->xdpy_height, + 0, + CopyFromParent, + InputOnly, + CopyFromParent, + CWOverrideRedirect|CWEventMask, + &attr); + } + } + + XSetWindowBorderWidth(wm->xdpy, MB_WM_CLIENT_XWIN(client), 0); + + XAddToSaveSet(wm->xdpy, MB_WM_CLIENT_XWIN(client)); + + XSelectInput(wm->xdpy, + MB_WM_CLIENT_XWIN(client), + PropertyChangeMask); +} + +static void +mb_wm_window_type_simple_stack (MBWindowManagerClient *client, + int flags) +{ + /* Stack to highest/lowest possible possition in stack */ + GList * t = mb_wm_client_get_transients (client); + + mb_wm_stack_move_top(client); + + g_list_foreach (t, (GFunc)mb_wm_client_stack, + (void*)flags); + + g_list_free (t); +} + +static void +mb_wm_window_type_simple_show (MBWindowManagerClient *client) +{ + /* mark dirty somehow */ + +} + +static void +mb_wm_window_type_simple_hide (MBWindowManagerClient *client) +{ + + /* mark dirty somehow */ + +} + +static void +mb_wm_window_type_simple_set_state_props (MBWindowManagerClient *c) +{ + unsigned long flags = c->window->ewmh_state; + Window xwin = c->window->xwindow; + MBWMManager *wm = c->wmref; + Display *xdpy = wm->xdpy; + CARD32 card32[2]; + Atom ewmh_state [MBWMClientWindowEWHMStatesCount]; + int ewmh_i = 0; + + card32[1] = None; + + if (mb_wm_client_is_mapped (c)) + card32[0] = NormalState; + else + card32[0] = IconicState; + + if (flags & MBWMClientWindowEWMHStateFullscreen) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN]; + + if (flags & MBWMClientWindowEWMHStateModal) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MODAL]; + + if (flags & MBWMClientWindowEWMHStateSticky) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_STICKY]; + + if (flags & MBWMClientWindowEWMHStateMaximisedVert) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT]; + if (flags & MBWMClientWindowEWMHStateMaximisedHorz) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ]; + if (flags & MBWMClientWindowEWMHStateShaded) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SHADED]; + + if (flags & MBWMClientWindowEWMHStateSkipTaskbar) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR]; + + if (flags & MBWMClientWindowEWMHStateSkipPager) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_PAGER]; + + if (flags & MBWMClientWindowEWMHStateAbove) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_BELOW]; + + if (flags & MBWMClientWindowEWMHStateDemandsAttention) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION]; + if (flags & MBWMClientWindowEWMHStateHidden) + ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_HIDDEN]; + + + XChangeProperty(xdpy, xwin, wm->atoms[MBWM_ATOM_WM_STATE], + wm->atoms[MBWM_ATOM_WM_STATE], 32, PropModeReplace, + (void *)&card32[0], 2); + + if (ewmh_i) + XChangeProperty (xdpy, xwin, wm->atoms[MBWM_ATOM_NET_WM_STATE], + XA_ATOM, 32, PropModeReplace, + (void*) &ewmh_state[0], ewmh_i); + else + XDeleteProperty (xdpy, xwin, wm->atoms[MBWM_ATOM_NET_WM_STATE]); +} + +static void +send_synthetic_configure_notify (MBWindowManagerClient *client) +{ + MBWMManager *wm = client->wmref; + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.event = MB_WM_CLIENT_XWIN(client); + ce.window = MB_WM_CLIENT_XWIN(client); + ce.x = client->window->geometry.x; + ce.y = client->window->geometry.y; + ce.width = client->window->geometry.width; + ce.height = client->window->geometry.height; + ce.border_width = 0; + ce.above = None; + ce.override_redirect = 0; + + XSendEvent(wm->xdpy, MB_WM_CLIENT_XWIN(client), False, + StructureNotifyMask, (XEvent *)&ce); +} + +static void +move_resize_client_xwin (MBWindowManagerClient *client, int x, int y, int w, int h) +{ + MBWMManager *wm = client->wmref; + + /* ICCCM says if you ignore a configure request or you respond + * by only moving/re-stacking the window - without a size change, + * then the WM must send a synthetic ConfigureNotify. + * + * NB: the above description assumes that a move/re-stack may be + * done by the WM by moving the frame (whereby a regular + * ConfigureNotify wouldn't be sent in direct response to the + * request which I think is the real point) + * + * NB: It's assumed that no cleverness is going elsewhere + * to optimise out calls to this function when the move/resize + * is obviously not needed (e.g. when just moving the frame + * of a client) + */ + if (mb_wm_client_needs_configure_request_ack (client) + && x == client->window->x_geometry.x + && y == client->window->x_geometry.y + && w == client->window->x_geometry.width + && h == client->window->x_geometry.height) + { + send_synthetic_configure_notify (client); + } + else + { + XMoveResizeWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client), + x, y, w, h); + client->window->x_geometry.x = x; + client->window->x_geometry.y = y; + client->window->x_geometry.width = w; + client->window->x_geometry.height = h; + +#if ENABLE_COMPOSITE + if (mb_wm_comp_mgr_enabled (wm->comp_mgr)) + { + mb_wm_comp_mgr_client_configure (client->cm_client); + } +#endif + } +} + +static void +mb_wm_window_type_simple_display_sync (MBWindowManagerClient *client) +{ + MBWMManager *wm = client->wmref; + MBWMClientWindow * win = client->window; + Bool fullscreen = (win->ewmh_state & MBWMClientWindowEWMHStateFullscreen); + + MBWM_MARK(); + + /* + * If we need to sync due to change in fullscreen state, we have reparent + * the client window to the frame/root window + */ + if (mb_wm_client_needs_fullscreen_sync (client)) + { + if (mb_wm_client_is_mapped (client)) + { + if (client->xwin_frame) + { + if (!fullscreen) + { + client->skip_unmaps++; + XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client), + client->xwin_frame, 0, 0); + XMapWindow(wm->xdpy, client->xwin_frame); + XMapSubwindows(wm->xdpy, client->xwin_frame); + + /* The frame is very likely the correct dimensions (since the + * app geometry is pretty static), but the client window is + * not (it was fullscreened) -- we need to force + * recalculation of the window frame dimensions, so that it + * is correct when we apply it below. + */ + mb_wm_client_request_geometry (client, + &client->frame_geometry, + MBWMClientReqGeomForced); + } + else + { + client->skip_unmaps++; + XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client), + wm->root_win->xwindow, 0, 0); + XUnmapWindow(wm->xdpy, client->xwin_frame); + XMapWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client)); + } + } + else + { + client->skip_unmaps++; + XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client), + wm->root_win->xwindow, + client->window->geometry.x, + client->window->geometry.y); + } + } + + if (wm->focused_client == client) + { + /* + * If we are the currently focused client, + * we need to reset the focus to RevertToPointerRoot, since the + * focus was lost during the implicit unmap. + */ + XSetInputFocus (wm->xdpy, client->window->xwindow, + RevertToPointerRoot, CurrentTime); + + } + } + + /* Sync up any geometry */ + + if (mb_wm_client_needs_geometry_sync (client)) + { + int x, y, w, h; + CARD32 wgeom[4]; + + mb_wm_util_trap_x_errors(); + + if (fullscreen || !client->xwin_frame) + { + + x = client->window->geometry.x; + y = client->window->geometry.y; + w = client->window->geometry.width; + h = client->window->geometry.height; + + move_resize_client_xwin (client, x, y, w, h); + + wgeom[0] = 0; + wgeom[1] = 0; + wgeom[2] = 0; + wgeom[3] = 0; + } + else + { + XMoveResizeWindow(wm->xdpy, + client->xwin_frame, + client->frame_geometry.x, + client->frame_geometry.y, + client->frame_geometry.width, + client->frame_geometry.height); + + /* FIXME: Call XConfigureWindow(w->dpy, e->window, + * value_mask,&xwc); here instead as can set border + * width = 0. + */ + x = client->window->geometry.x - client->frame_geometry.x; + y = client->window->geometry.y - client->frame_geometry.y; + w = client->window->geometry.width; + h = client->window->geometry.height; + + move_resize_client_xwin (client, x, y, w, h); + + wgeom[0] = x; + wgeom[1] = client->frame_geometry.width - w - x; + wgeom[2] = y; + wgeom[3] = client->frame_geometry.height - h - y; + } + + XChangeProperty(wm->xdpy, + MB_WM_CLIENT_XWIN(client), + wm->atoms[MBWM_ATOM_NET_FRAME_EXTENTS], + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&wgeom[0], 4); + + /* FIXME: need flags to handle other stuff like configure events etc */ + + /* Resize any decor */ + g_list_foreach(client->decor, + (GFunc)mb_wm_decor_handle_resize, + NULL); + + mb_wm_util_untrap_x_errors(); + } + else if (mb_wm_client_needs_configure_request_ack (client)) + send_synthetic_configure_notify (client); + + + /* Handle any mapping - should be visible state ? */ + + if (mb_wm_client_needs_visibility_sync (client)) + { + mb_wm_util_trap_x_errors(); + + if (mb_wm_client_is_mapped (client)) + { + if (client->xwin_frame) + { + if (!fullscreen) + { + XMapWindow (wm->xdpy, client->xwin_frame); + XMapSubwindows (wm->xdpy, client->xwin_frame); + } + else + { + XUnmapWindow (wm->xdpy, client->xwin_frame); + XMapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client)); + } + } + else + { + XMapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client)); + } + + if (client->xwin_modal_blocker) + XMapWindow (wm->xdpy, client->xwin_modal_blocker); + } + else + { + if (client->xwin_frame) + { + XUnmapWindow (wm->xdpy, client->xwin_frame); + XUnmapSubwindows (wm->xdpy, client->xwin_frame); + } + else + XUnmapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client)); + + + if (client->xwin_modal_blocker) + XUnmapWindow (wm->xdpy, client->xwin_modal_blocker); + + } + + mb_wm_window_type_simple_set_state_props (client); + mb_wm_util_untrap_x_errors(); + } + + /* Paint any decor */ + + mb_wm_util_trap_x_errors(); + + if (mb_wm_client_needs_decor_sync (client)) + { + /* + * First, we set the base shape mask, if needed, so that individual + * decors can add themselves to it. + */ +#ifdef HAVE_XEXT + if (mb_wm_theme_is_client_shaped (wm->theme, client)) + { + XRectangle rects[1]; + + rects[0].x = client->window->geometry.x - client->frame_geometry.x; + rects[0].y = client->window->geometry.y - client->frame_geometry.y; + rects[0].width = client->window->geometry.width; + rects[0].height = client->window->geometry.height; + + XShapeCombineRectangles (wm->xdpy, client->xwin_frame, + ShapeBounding, + 0, 0, rects, 1, ShapeSet, 0 ); + } +#endif + + if (fullscreen) + { + if (client->xwin_frame) + XUnmapWindow(wm->xdpy, client->xwin_frame); + } + else + { + if (client->xwin_frame) + XMapWindow(wm->xdpy, client->xwin_frame); + } + + g_list_foreach(client->decor, + (GFunc)mb_wm_decor_handle_repaint, + NULL); + + + } + + mb_wm_util_untrap_x_errors(); + + mb_wm_util_trap_x_errors(); + XSync(wm->xdpy, False); + mb_wm_util_untrap_x_errors(); +} + +/* Note request geometry always called by layout manager */ +static Bool +mb_wm_window_type_simple_request_geometry (MBWindowManagerClient *client, + MBGeometry *new_geometry, + MBWMClientReqGeomType flags) +{ + /* + * flags are + * + * MBReqGeomDontCommit + * MBReqGeomIsViaConfigureReq + * MBReqGeomIsViaUserAction + * MBReqGeomIsViaLayoutManager + * MBReqGeomForced + * + */ + + /* Dont actually change anything - mb_wm_core_sync() should do that + * but mark dirty and 'queue any extra info like configure req'. + */ + + if (flags & MBWMClientReqGeomIsViaLayoutManager) + { + MBWM_DBG("called with 'MBWMClientReqGeomIsViaLayoutManager' %ix%i+%i+%i", + new_geometry->width, + new_geometry->height, + new_geometry->x, + new_geometry->y); + + client->frame_geometry.x = new_geometry->x; + client->frame_geometry.y = new_geometry->y; + client->frame_geometry.width = new_geometry->width; + client->frame_geometry.height = new_geometry->height; + + client->window->geometry.x = client->frame_geometry.x + 4; + client->window->geometry.y = client->frame_geometry.y + 4; + client->window->geometry.width = client->frame_geometry.width - 8; + client->window->geometry.height = client->frame_geometry.height - 8; + + mb_wm_client_geometry_mark_dirty (client); + + return True; /* Geometry accepted */ + } + + return True; +} + +static Bool +mb_wm_window_type_simple_focus (MBWindowManagerClient *client) +{ + static Window last_focused = None; + MBWMManager *wm = client->wmref; + Window xwin = client->window->xwindow; + + if (!mb_wm_client_want_focus (client)) + return False; + + if (xwin == last_focused) + return False; + + mb_wm_util_trap_x_errors (); + + XSetInputFocus(wm->xdpy, xwin, RevertToPointerRoot, CurrentTime); + + XChangeProperty(wm->xdpy, wm->root_win->xwindow, + wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *)&xwin, 1); + + if (mb_wm_util_untrap_x_errors()) + return False; + + last_focused = xwin; + + return True; +} + +void base_foo(void) +{ + ; /* nasty hack to workaround linking issues WTF... + * use .la's rather than .a's ?? + */ +} |