/* * Matchbox Window Manager II - A lightweight window manager not for the * desktop. * * Authored By Matthew Allum * * 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-config.h" #include "mb-wm-client.h" #include "mb-wm-manager.h" #include "mb-wm-theme.h" #include #include #if ENABLE_COMPOSITE #include #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); MBWMManager * wm = client->wmref; GList * 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_manager_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; GList * l2 = l; c->transient_for = NULL; XUnmapWindow (wm->xdpy, c->window->xwindow); l = l->next; g_list_free_1 (l2); } } static Bool mb_wm_client_on_property_change (MBWMClientWindow *window, int property, void *userdata); static Bool mb_wm_client_on_theme_change (MBWMManager * 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; MBWMManager *wm = NULL; MBWMClientWindow *win = NULL; MBWMObjectProp prop; int status; prop = va_arg(vap, MBWMObjectProp); while (prop) { switch (prop) { case MBWMObjectPropWm: wm = va_arg(vap, MBWMManager *); 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), MBWMManagerSignalThemeChange, (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_manager_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_manager_display_sync_queue (client->wmref, MBWMSyncStacking); client->priv->sync_state |= MBWMSyncStacking; } void mb_wm_client_geometry_mark_dirty (MBWindowManagerClient *client) { mb_wm_manager_display_sync_queue (client->wmref, MBWMSyncGeometry); client->priv->sync_state |= MBWMSyncGeometry; } void mb_wm_client_visibility_mark_dirty (MBWindowManagerClient *client) { mb_wm_manager_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_manager_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_manager_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) { GList * 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_window_type_simple/class_new ? */ mb_wm_client_new (MBWMManager *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_manager_unfocus_window (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 * MBWMManager 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) { GList *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 = g_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 = g_list_remove(client->transients, transient); if (client->last_focused_transient == transient) client->last_focused_transient = transient->next_focused_client; } GList* mb_wm_client_get_transients (MBWindowManagerClient *client) { GList *trans = NULL; GList *l = client->transients; Window xgroup = client->window->xwin_group; MBWindowManagerClient *c; MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); while (l) { trans = g_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 = g_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) { MBWMManager *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) { MBWMManager *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) { MBWMManager *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_manager_handle_hung_window (client->wmref, client); mb_wm_client_ping_stop (client); return False; } void mb_wm_client_ping_start (MBWindowManagerClient *client) { MBWMManager * wm = client->wmref; MBWMClientWindowProtos protos = client->window->protos; if (!(protos & MBWMClientWindowProtosPing)) return; if (client->ping_cb_id) return; client->ping_cb_id = g_timeout_add (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) { if (!client->ping_cb_id) return; g_source_remove (client->ping_cb_id); client->ping_cb_id = 0; } void mb_wm_client_shutdown (MBWindowManagerClient *client) { char buf[257]; int sig = 9; MBWMManager *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) { MBWMManager *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) { MBWMManager *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_manager_activate_window(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_manager_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; MBWMManager * 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) { GList * 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; }