diff options
Diffstat (limited to 'matchbox2/mb-wm-client.c')
-rw-r--r-- | matchbox2/mb-wm-client.c | 1120 |
1 files changed, 1120 insertions, 0 deletions
diff --git a/matchbox2/mb-wm-client.c b/matchbox2/mb-wm-client.c new file mode 100644 index 0000000..f88a8d8 --- /dev/null +++ b/matchbox2/mb-wm-client.c @@ -0,0 +1,1120 @@ +/* + * 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 "mb-wm.h" +#include "mb-wm-theme.h" + +#include <unistd.h> +#include <signal.h> + +#if ENABLE_COMPOSITE +#include <X11/extensions/Xrender.h> +#endif + +struct MBWindowManagerClientPriv +{ + Bool realized; + Bool mapped; + Bool iconizing; + Bool hiding_from_desktop; + MBWMSyncType sync_state; +}; + +static void +mb_wm_client_destroy (MBWMObject *obj) +{ + MBWindowManagerClient * client = MB_WM_CLIENT(obj); + MBWindowManager * wm = client->wmref; + MBWMList * l = client->decor; + + if (client->sig_theme_change_id) + mb_wm_object_signal_disconnect (MB_WM_OBJECT (wm), + client->sig_theme_change_id); + client->sig_theme_change_id = 0; + + if (client->sig_prop_change_id) + mb_wm_object_signal_disconnect (MB_WM_OBJECT (client->window), + client->sig_prop_change_id); + + client->sig_prop_change_id = 0; + + /* Must call mb_wm_client_ping_stop rather than + * mb_wm_main_context_timeout_handler_remove() to prevent a race condition + * segfault in the timeout list manipulation + */ + mb_wm_client_ping_stop (client); + +#if ENABLE_COMPOSITE + if (mb_wm_compositing_enabled (wm)) + { + mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client); + } +#endif + + mb_wm_object_unref (MB_WM_OBJECT (client->window)); + + while (l) + { + mb_wm_object_unref (l->data); + l = l->next; + } + + if (client->transient_for) + mb_wm_client_remove_transient (client->transient_for, client); + + /* If we have transient windows, we need to make sure they are unmapped; for + * application dialogs this will happen automatically, but not for external + * transients, such as input windows. + * + * We also have to make sure that the transients no longer refer to this + * client, which is about the be destroyed. + */ + l = client->transients; + while (l) + { + MBWindowManagerClient * c = l->data; + MBWMList * l2 = l; + + c->transient_for = NULL; + XUnmapWindow (wm->xdpy, c->window->xwindow); + + l = l->next; + + free (l2); + } +} + +static Bool +mb_wm_client_on_property_change (MBWMClientWindow *window, + int property, + void *userdata); + +static Bool +mb_wm_client_on_theme_change (MBWindowManager * wm, int signal, + MBWindowManagerClient * client) +{ + mb_wm_client_theme_change (client); + return False; +} + + +static int +mb_wm_client_init (MBWMObject *obj, va_list vap) +{ + MBWindowManagerClient *client; + MBWindowManager *wm = NULL; + MBWMClientWindow *win = NULL; + MBWMObjectProp prop; + int status; + + prop = va_arg(vap, MBWMObjectProp); + while (prop) + { + switch (prop) + { + case MBWMObjectPropWm: + wm = va_arg(vap, MBWindowManager *); + break; + case MBWMObjectPropClientWindow: + win = va_arg(vap, MBWMClientWindow *); + break; + default: + MBWMO_PROP_EAT (vap, prop); + } + + prop = va_arg(vap, MBWMObjectProp); + } + + MBWM_MARK(); + + client = MB_WM_CLIENT(obj); + client->priv = mb_wm_util_malloc0(sizeof(MBWindowManagerClientPriv)); + + client->window = win; + client->wmref = wm; + client->ping_timeout = 1000; + + if (wm->theme) + { + client->layout_hints = + mb_wm_theme_get_client_layout_hints (wm->theme, client); + } + + /* sync with client window */ + mb_wm_client_on_property_change (win, MBWM_WINDOW_PROP_ALL, client); + + /* Handle underlying property changes */ + client->sig_prop_change_id = + mb_wm_object_signal_connect (MB_WM_OBJECT (win), + MBWM_WINDOW_PROP_ALL, + (MBWMObjectCallbackFunc)mb_wm_client_on_property_change, + client); + + client->sig_theme_change_id = + mb_wm_object_signal_connect (MB_WM_OBJECT (wm), + MBWindowManagerSignalThemeChange, + (MBWMObjectCallbackFunc)mb_wm_client_on_theme_change, + client); + + status = XGrabButton(wm->xdpy, Button1, 0, win->xwindow, True, + ButtonPressMask, + GrabModeSync, GrabModeSync, None, None); + + MBWM_NOTE (CLIENT, "XGrabButton() returned status %d for client window %x", + status, + win->xwindow); + +#if ENABLE_COMPOSITE + { + XRenderPictFormat *format; + + format = XRenderFindVisualFormat (wm->xdpy, win->visual); + + if (format && format->type == PictTypeDirect && + format->direct.alphaMask) + { + client->is_argb32 = True; + } + } +#endif + + return 1; +} + +int +mb_wm_client_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWindowManagerClientClass), + sizeof (MBWindowManagerClient), + mb_wm_client_init, + mb_wm_client_destroy, + NULL + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); + } + + return type; +} + +void +mb_wm_client_fullscreen_mark_dirty (MBWindowManagerClient *client) +{ + /* fullscreen implies geometry and visibility sync */ + mb_wm_display_sync_queue (client->wmref, + MBWMSyncFullscreen | + MBWMSyncVisibility | MBWMSyncGeometry); + + client->priv->sync_state |= (MBWMSyncFullscreen | + MBWMSyncGeometry | + MBWMSyncVisibility); +} + +void +mb_wm_client_stacking_mark_dirty (MBWindowManagerClient *client) +{ + mb_wm_display_sync_queue (client->wmref, MBWMSyncStacking); + client->priv->sync_state |= MBWMSyncStacking; +} + +void +mb_wm_client_geometry_mark_dirty (MBWindowManagerClient *client) +{ + mb_wm_display_sync_queue (client->wmref, MBWMSyncGeometry); + + client->priv->sync_state |= MBWMSyncGeometry; +} + +void +mb_wm_client_visibility_mark_dirty (MBWindowManagerClient *client) +{ + mb_wm_display_sync_queue (client->wmref, MBWMSyncVisibility); + + client->priv->sync_state |= MBWMSyncVisibility; + + MBWM_DBG(" sync state: %i", client->priv->sync_state); +} + +void +mb_wm_client_configure_request_ack_queue (MBWindowManagerClient *client) +{ + mb_wm_display_sync_queue (client->wmref, MBWMSyncConfigRequestAck); + + client->priv->sync_state |= MBWMSyncConfigRequestAck; + + MBWM_DBG(" sync state: %i", client->priv->sync_state); +} + +Bool +mb_wm_client_needs_configure_request_ack (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncConfigRequestAck); +} + +void +mb_wm_client_decor_mark_dirty (MBWindowManagerClient *client) +{ + mb_wm_display_sync_queue (client->wmref, MBWMSyncDecor); + + client->priv->sync_state |= MBWMSyncDecor; + + MBWM_DBG(" sync state: %i", client->priv->sync_state); +} + +Bool +mb_wm_client_needs_fullscreen_sync (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncFullscreen); +} + +static Bool +mb_wm_client_on_property_change (MBWMClientWindow *window, + int property, + void *userdata) +{ + MBWindowManagerClient * client = MB_WM_CLIENT (userdata); + + if (property & MBWM_WINDOW_PROP_NAME) + { + MBWMList * l = client->decor; + while (l) + { + MBWMDecor * decor = l->data; + + if (mb_wm_decor_get_type (decor) == MBWMDecorTypeNorth) + { + mb_wm_decor_mark_title_dirty (decor); + break; + } + + l = l->next; + } + } + + if (property & MBWM_WINDOW_PROP_GEOMETRY) + mb_wm_client_geometry_mark_dirty (client); + +#if ENABLE_COMPOSITE + if ((property & MBWM_WINDOW_PROP_CM_TRANSLUCENCY) && + client->cm_client && mb_wm_comp_mgr_enabled (client->wmref->comp_mgr)) + { + mb_wm_comp_mgr_client_repair (client->cm_client); + } +#endif + + return False; +} + +MBWindowManagerClient* /* FIXME: rename to mb_wm_client_base/class_new ? */ +mb_wm_client_new (MBWindowManager *wm, MBWMClientWindow *win) +{ + MBWindowManagerClient *client = NULL; + + client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT, + MBWMObjectPropWm, wm, + MBWMObjectPropClientWindow, win, + NULL)); + + return client; +} + +void +mb_wm_client_realize (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + if (client->priv->realized) + return; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->realize) + klass->realize(client); + + client->priv->realized = True; +} + +Bool +mb_wm_client_is_realized (MBWindowManagerClient *client) +{ + return client->priv->realized; +} + + +/* ## Stacking ## */ + + +void +mb_wm_client_stack (MBWindowManagerClient *client, + int flags) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->stack) + { + klass->stack(client, flags); + + /* Schedule stack sync, but not if the client is of override type */ + if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeOverride) + mb_wm_client_stacking_mark_dirty (client); + } +} + +Bool +mb_wm_client_needs_stack_sync (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncStacking); +} + +void +mb_wm_client_show (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->show) + klass->show (client); + + client->priv->mapped = True; + + /* Make sure any Hidden state flag is cleared */ + mb_wm_client_set_state (client, + MBWM_ATOM_NET_WM_STATE_HIDDEN, + MBWMClientWindowStateChangeRemove); + + mb_wm_client_visibility_mark_dirty (client); +} + +void +mb_wm_client_hide (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->hide) + { + klass->hide (client); + + client->priv->mapped = False; + + mb_wm_unfocus_client (client->wmref, client); + mb_wm_client_visibility_mark_dirty (client); + } +} + +/* + * The focus processing is split into two stages, client and WM + * + * The client stage is handled by this function, with the return value + * of True indicating that the focus has changed. + * + * NB: This function should be considered protected and only called by the + * MBWindowManager object code. + */ +Bool +mb_wm_client_focus (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + Bool ret = False; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->focus) + ret = klass->focus(client); + + if (ret) + { + /* + * If this client is transient, store it with the parent; if it is not + * transient, reset the last transient field + */ + if (client->transient_for) + client->transient_for->last_focused_transient = client; + else + client->last_focused_transient = NULL; + } + + return ret; +} + +Bool +mb_wm_client_want_focus (MBWindowManagerClient *client) +{ + return (client->window->want_key_input != False); +} + +Bool +mb_wm_client_needs_visibility_sync (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncVisibility); +} + +Bool +mb_wm_client_needs_geometry_sync (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncGeometry); +} + +Bool +mb_wm_client_needs_decor_sync (MBWindowManagerClient *client) +{ + return (client->priv->sync_state & MBWMSyncDecor); +} + +Bool +mb_wm_client_needs_sync (MBWindowManagerClient *client) +{ + MBWM_DBG("sync_state: %i", client->priv->sync_state); + + return client->priv->sync_state; +} + +Bool +mb_wm_client_is_mapped (MBWindowManagerClient *client) +{ + return client->priv->mapped; +} + +void +mb_wm_client_display_sync (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->sync) + klass->sync (client); + + client->priv->sync_state = 0; +} + + +Bool +mb_wm_client_request_geometry (MBWindowManagerClient *client, + MBGeometry *new_geometry, + MBWMClientReqGeomType flags) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->geometry) + return klass->geometry(client, new_geometry, flags); + + return False; +} + +MBWMClientLayoutHints +mb_wm_client_get_layout_hints (MBWindowManagerClient *client) +{ + if ((client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen)) + { + if (client->layout_hints & LayoutPrefVisible) + return (LayoutPrefFullscreen | LayoutPrefVisible); + else + return LayoutPrefFullscreen; + } + + return client->layout_hints; +} + +void +mb_wm_client_set_layout_hints (MBWindowManagerClient *client, + MBWMClientLayoutHints hints) +{ + client->layout_hints = hints; +} + +void +mb_wm_client_set_layout_hint (MBWindowManagerClient *client, + MBWMClientLayoutHints hint, + Bool state) +{ + if (state) + client->layout_hints |= hint; + else + client->layout_hints &= ~hint; +} + +void /* needs to be boolean, client may not have any coverage */ +mb_wm_client_get_coverage (MBWindowManagerClient *client, + MBGeometry *coverage) +{ + MBGeometry *geometry; + + if (!client->xwin_frame) + geometry = &client->window->geometry; + else + geometry = &client->frame_geometry; + + coverage->x = geometry->x; + coverage->y = geometry->y; + coverage->width = geometry->width; + coverage->height = geometry->height; +} + +void +mb_wm_client_add_transient (MBWindowManagerClient *client, + MBWindowManagerClient *transient) +{ + MBWMList *l; + + if (transient == NULL || client == NULL) + return; + + transient->transient_for = client; + + /* + * Make sure that each transient is only added once (theoretically it should + * be, but it is very easy for a derived class to call this function without + * realizing the parent has dones so). + */ + l = client->transients; + while (l) + { + if (l->data == transient) + return; + + l = l->next; + } + + client->transients = mb_wm_util_list_append(client->transients, transient); +} + +void +mb_wm_client_remove_transient (MBWindowManagerClient *client, + MBWindowManagerClient *transient) +{ + if (!transient || !client || !client->transients) + return; + + transient->transient_for = NULL; + + client->transients = mb_wm_util_list_remove(client->transients, transient); + + if (client->last_focused_transient == transient) + client->last_focused_transient = transient->next_focused_client; +} + +MBWMList* +mb_wm_client_get_transients (MBWindowManagerClient *client) +{ + MBWMList *trans = NULL; + MBWMList *l = client->transients; + Window xgroup = client->window->xwin_group; + MBWindowManagerClient *c; + MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); + + while (l) + { + trans = mb_wm_util_list_prepend (trans, l->data); + l = l->next; + } + + /* If this is an application or desktop that are part of an group, + * we add any other transients that are part of the group to the list. + */ + if (xgroup && + (c_type == MBWMClientTypeApp || c_type == MBWMClientTypeDesktop)) + { + mb_wm_stack_enumerate (client->wmref, c) + if (c != client && + c->transient_for && c->window->xwin_group == xgroup) + { + MBWindowManagerClient * t = c->transient_for; + + /* Only add it if it is not directly transiet for our client (in + * which case it is already in the list + * + * Find the bottom level transient + */ + while (t && t->transient_for) + t = t->transient_for; + + if (!t || (MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeApp || + MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeDesktop)) + { + trans = mb_wm_util_list_prepend (trans, c); + } + } + } + + return trans; +} + +MBWindowManagerClient* +mb_wm_client_get_transient_for (MBWindowManagerClient *client) +{ + return client->transient_for; +} + + +const char* +mb_wm_client_get_name (MBWindowManagerClient *client) +{ + if (!client->window) + return NULL; + + return client->window->name; +} + +void +mb_wm_client_deliver_message (MBWindowManagerClient *client, + Atom delivery_atom, + unsigned long data0, + unsigned long data1, + unsigned long data2, + unsigned long data3, + unsigned long data4) +{ + MBWindowManager *wm = client->wmref; + Window xwin = client->window->xwindow; + XEvent ev; + + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = xwin; + ev.xclient.message_type = delivery_atom; + ev.xclient.format = 32; + ev.xclient.data.l[0] = data0; + ev.xclient.data.l[1] = data1; + ev.xclient.data.l[2] = data2; + ev.xclient.data.l[3] = data3; + ev.xclient.data.l[4] = data4; + + XSendEvent(wm->xdpy, xwin, False, NoEventMask, &ev); + + XSync(wm->xdpy, False); +} + +void +mb_wm_client_deliver_wm_protocol (MBWindowManagerClient *client, + Atom protocol) +{ + MBWindowManager *wm = client->wmref; + + mb_wm_client_deliver_message (client, wm->atoms[MBWM_ATOM_WM_PROTOCOLS], + protocol, CurrentTime, 0, 0, 0); +} + +static void +mb_wm_client_deliver_ping_protocol (MBWindowManagerClient *client) +{ + MBWindowManager *wm = client->wmref; + + mb_wm_client_deliver_message (client, + wm->atoms[MBWM_ATOM_WM_PROTOCOLS], + wm->atoms[MBWM_ATOM_NET_WM_PING], + CurrentTime, + client->window->xwindow, + 0, 0); +} + +static Bool +mb_wm_client_ping_timeout_cb (void * userdata) +{ + MBWindowManagerClient * client = userdata; + + mb_wm_handle_hang_client (client->wmref, client); + + mb_wm_client_ping_stop (client); + return False; +} + +void +mb_wm_client_ping_start (MBWindowManagerClient *client) +{ + MBWindowManager * wm = client->wmref; + MBWMMainContext * ctx = wm->main_ctx; + MBWMClientWindowProtos protos = client->window->protos; + + if (!(protos & MBWMClientWindowProtosPing)) + return; + + if (client->ping_cb_id) + return; + + client->ping_cb_id = + mb_wm_main_context_timeout_handler_add (ctx, client->ping_timeout, + mb_wm_client_ping_timeout_cb, + client); + + mb_wm_client_deliver_ping_protocol (client); +} + +void +mb_wm_client_ping_stop (MBWindowManagerClient *client) +{ + MBWMMainContext * ctx = client->wmref->main_ctx; + + if (!client->ping_cb_id) + return; + + mb_wm_main_context_timeout_handler_remove (ctx, client->ping_cb_id); + client->ping_cb_id = 0; +} + +void +mb_wm_client_shutdown (MBWindowManagerClient *client) +{ + char buf[257]; + int sig = 9; + MBWindowManager *wm = client->wmref; + MBWMClientWindow *win = client->window; + Window xwin = client->window->xwindow; + const char *machine = win->machine; + pid_t pid = win->pid; + + if (machine && pid && (gethostname (buf, sizeof(buf)-1) == 0)) + { + if (!strcmp (buf, machine)) + { + if (kill (pid, sig) >= 0) + return; + } + } + + XKillClient(wm->xdpy, xwin); +} + +void +mb_wm_client_deliver_delete (MBWindowManagerClient *client) +{ + MBWindowManager *wm = client->wmref; + MBWMClientWindowProtos protos = client->window->protos; + + if ((protos & MBWMClientWindowProtosDelete)) + { + mb_wm_client_deliver_wm_protocol (client, + wm->atoms[MBWM_ATOM_WM_DELETE_WINDOW]); + + /* NB: It is not appropriate (or even possible) to try and + * determine a failure to respond to a WM_DELETE, since it + * would be reasonable for a client to put up a confirmation + * dialog in response to a WM_DELETE and do nothing if the + * user cancels the operation (because it was an accident) + * + * The NET_WM_PING protocol is the right way to determine an + * unresponsive client and we always send a ping (if the + * client supports the protocol) when issuing a WM_DELETE. + */ + + mb_wm_client_ping_start (client); + } + else + mb_wm_client_shutdown (client); +} + +void +mb_wm_client_set_state (MBWindowManagerClient *client, + MBWMAtom state, + MBWMClientWindowStateChange state_op) +{ + MBWindowManager *wm = client->wmref; + MBWMClientWindow *win = client->window; + Bool old_state; + Bool new_state; + Bool activate = True; + MBWMClientWindowEWMHState state_flag; + + switch (state) + { + case MBWM_ATOM_NET_WM_STATE_FULLSCREEN: + state_flag = MBWMClientWindowEWMHStateFullscreen; + break; + case MBWM_ATOM_NET_WM_STATE_ABOVE: + state_flag = MBWMClientWindowEWMHStateAbove; + break; + case MBWM_ATOM_NET_WM_STATE_HIDDEN: + state_flag = MBWMClientWindowEWMHStateHidden; + break; + case MBWM_ATOM_NET_WM_STATE_MODAL: + case MBWM_ATOM_NET_WM_STATE_STICKY: + case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT: + case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ: + case MBWM_ATOM_NET_WM_STATE_SHADED: + case MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR: + case MBWM_ATOM_NET_WM_STATE_SKIP_PAGER: + case MBWM_ATOM_NET_WM_STATE_BELOW: + case MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION: + default: + return; /* not handled yet */ + } + + old_state = (win->ewmh_state & state_flag); + + switch (state_op) + { + case MBWMClientWindowStateChangeRemove: + new_state = False; + break; + case MBWMClientWindowStateChangeAdd: + new_state = True; + break; + case MBWMClientWindowStateChangeToggle: + new_state = !old_state; + break; + } + + if (new_state == old_state) + return; + + if (new_state) + { + win->ewmh_state |= state_flag; + } + else + { + win->ewmh_state &= ~state_flag; + } + + if (state_flag & MBWMClientWindowEWMHStateHidden) + { + if (new_state) + mb_wm_client_hide (client); + else + mb_wm_client_show (client); + + return; + } + + if ((state_flag & MBWMClientWindowEWMHStateFullscreen)) + { + mb_wm_client_fullscreen_mark_dirty (client); + } + + /* + * FIXME -- resize && move, possibly redraw decors when returning from + * fullscreen + */ + if (activate) + mb_wm_activate_client(wm, client); +} + +Bool +mb_wm_client_ping_in_progress (MBWindowManagerClient * client) +{ + return (client->ping_cb_id != 0); +} + +void +mb_wm_client_theme_change (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->theme_change) + klass->theme_change (client); +} + +/* + * Cleanup any transient relationships this client might have + * (we need to do this when the client window unmaps to ensure correct + * functioning of the stack). + */ +void +mb_wm_client_detransitise (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + if (!client->transient_for) + return; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->detransitise) + klass->detransitise (client); + + mb_wm_client_remove_transient (client->transient_for, client); +} + +Bool +mb_wm_client_is_iconizing (MBWindowManagerClient *client) +{ + return client->priv->iconizing; +} + +void +mb_wm_client_reset_iconizing (MBWindowManagerClient *client) +{ + client->priv->iconizing = False; +} + +void +mb_wm_client_iconize (MBWindowManagerClient *client) +{ + /* + * Set the iconizing flag and put the window into hidden state + * This triggers an umap event, at which point the client gets unmanaged + * by the window manager. + */ +#if ENABLE_COMPOSITE + /* + * We cannot iconize the client until the effect finished, otherwise it + * will unmap before the effect takes place, so we do this in the callback. + */ + if (mb_wm_compositing_enabled (client->wmref)) + { + mb_wm_comp_mgr_do_effect (client->wmref->comp_mgr, client, + MBWMCompMgrClientEventMinimize); + } +#endif + + client->priv->iconizing = True; + + + mb_wm_client_set_state (client, + MBWM_ATOM_NET_WM_STATE_HIDDEN, + MBWMClientWindowStateChangeAdd); +} + +int +mb_wm_client_title_height (MBWindowManagerClient *client) +{ + MBWMClientWindow * win = client->window; + MBWindowManager * wm = client->wmref; + int north; + + if (!wm->theme || + mb_wm_client_window_is_state_set (win, + MBWMClientWindowEWMHStateFullscreen)) + { + return 0; + } + + + mb_wm_theme_get_decor_dimensions (wm->theme, client, + &north, NULL, NULL, NULL); + + return north; +} + +Bool +mb_wm_client_is_modal (MBWindowManagerClient *client) +{ + return mb_wm_client_window_is_state_set (client->window, + MBWMClientWindowEWMHStateModal); +} + +Bool +mb_wm_client_owns_xwindow (MBWindowManagerClient *client, Window xwin) +{ + MBWMList * l; + + if (client->xwin_frame == xwin || client->window->xwindow == xwin) + return True; + + l = client->decor; + while (l) + { + MBWMDecor * d = l->data; + + if (d->xwin == xwin) + return True; + + l = l->next; + } + + return False; +} + +MBWMStackLayerType +mb_wm_client_get_stacking_layer (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *klass; + + klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client))); + + if (klass->stacking_layer) + return klass->stacking_layer (client); + + return client->stacking_layer; +} + +Bool +mb_wm_client_is_argb32 (MBWindowManagerClient *client) +{ + return client->is_argb32; +} + +void +mb_wm_client_set_desktop (MBWindowManagerClient * client, int desktop) +{ + client->desktop = desktop; +} + +int +mb_wm_client_get_desktop (MBWindowManagerClient * client) +{ + return client->desktop; +} + +void +mb_wm_client_desktop_change (MBWindowManagerClient * client, int desktop) +{ + if (client->desktop < 0) + return; + + if (client->desktop == desktop) + { + mb_wm_client_set_state (client, + MBWM_ATOM_NET_WM_STATE_HIDDEN, + MBWMClientWindowStateChangeRemove); + + /* + * NB -- we do not reset the hiding_from_desktop flag here + * since it is there to indicate to the WM that the window is + * mapping because of the desktop change; the WM resets it when + * it get the map-notify for it. + */ + } + else + { + client->priv->hiding_from_desktop = True; + + mb_wm_client_set_state (client, + MBWM_ATOM_NET_WM_STATE_HIDDEN, + MBWMClientWindowStateChangeAdd); + } +} + +Bool +mb_wm_client_is_hiding_from_desktop (MBWindowManagerClient * client) +{ + return client->priv->hiding_from_desktop; +} + +void +mb_wm_client_reset_hiding_from_desktop (MBWindowManagerClient * client) +{ + client->priv->hiding_from_desktop = False; +} + |