/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /***************************************************************************** * * File: WmFP.c * * Project: CDE * * Description: This file contains functions used between the window manager * and front panel. * * (c) Copyright 1993, 1994 Hewlett-Packard Company * (c) Copyright 1993, 1994 International Business Machines Corp. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc. * ****************************************************************************/ #include "WmGlobal.h" #include
#include
#include
#include
#include
#include
#include
#include
#include #include #include #include #include #include #include #include #include #include #include "PanelSP.h" #include "DataBaseLoad.h" #include "UI.h" #include "WmPanelP.h" #include "WmManage.h" #include #include #include #include extern void SubpanelTornEventHandler (Widget, XtPointer, XEvent *, Boolean *); extern void WorkspaceModifyCB (Widget, Atom, int, XtPointer); extern void SessionRestoreData (void); extern void UnManageWindow (ClientData *pCD); extern void WorkspaceAdjustPanelPosition (Position x, Position y, Dimension width, Dimension height); static void PushRecallSetData (); static void EmbeddedClientSetData (); static void EmbeddedClientSetGeometry (WmFpEmbeddedClientData *); /************************************************************************ * * EmbeddedClientReposition * This function moves client windows within the main panel after * controls have been resized. * * Inputs: icon - the icon of the embedded client to be repositioned * x - the position of the resized control * adjust - how much to move the window * ************************************************************************/ void EmbeddedClientReposition (Widget icon, Position x, Dimension adjust) { WmFpEmbeddedClientList embedded_client_list = (WmFpEmbeddedClientList) panel.embedded_client_list; int i; for (i = 0; i < panel.embedded_client_count; i++) { if (XtParent (icon) == XtParent (embedded_client_list[i].wControl) && embedded_client_list[i].x > x) { if (embedded_client_list[i].pCD != NULL) { embedded_client_list[i].x += adjust; XMoveWindow (XtDisplay (panel.shell), embedded_client_list[i].pCD->client, embedded_client_list[i].x, embedded_client_list[i].y); } else embedded_client_list[i].x += adjust; } } } /************************************************************************ * * EmbeddedClientReparent * This function sets of the data necessary to call the window * manager function which reparents an embedded client to a new * control. * * Inputs: client_name - the name of the client to be reparented. * icon - the widget that is to contain the client. * parent_win - the parent win to reparent the client to. * ************************************************************************/ void EmbeddedClientReparent (char * client_name, Widget icon) { WmFpEmbeddedClientList embedded_client_list = (WmFpEmbeddedClientList) panel.embedded_client_list; int i; for (i = 0; i < panel.embedded_client_count; i++) { if (strcmp (client_name, embedded_client_list[i].pchResName) == 0) break; } /* Try to reparent the client to/from the main panel. If this */ /* fails, it is because of a dtwm restart and the clients have */ /* not yet been grabbed. So just reset the embedded client data */ if (ReparentEmbeddedClient (&embedded_client_list[i], icon, XtWindow (XtParent (icon)), XtX (icon) + 3, XtY (icon) + 3, XtWidth(icon) - 6, XtHeight(icon) - 6) == False) { embedded_client_list[i].wControl = icon; embedded_client_list[i].winParent = XtWindow (XtParent (icon)); embedded_client_list[i].x = XtX (icon) + 3; embedded_client_list[i].y = XtY (icon) + 3; embedded_client_list[i].width = XtWidth (icon) - 6; embedded_client_list[i].height = XtHeight (icon) - 6; } } /************************************************************************ * * EmbeddedClientRegister * This function adds a control to the list of embedded client controls * and resets, if necessary, the Window Managers pointers to the list. * * Inputs: * control_data - the pointer to the ControlData * structure of * the control to be installed or removed. * * install - Boolean indicating whether to add or remove the control * from the push recall list. * ************************************************************************/ void EmbeddedClientRegister (ControlData * control_data, Boolean install) { char * client_name; Window client_window; int i, j; WmFpEmbeddedClientList embedded_client_list = (WmFpEmbeddedClientList) panel.embedded_client_list; WmFpEmbeddedClientData * embedded_client = NULL; if ((intptr_t) control_data-> element_values[CONTROL_TYPE].parsed_value != CONTROL_CLIENT) return; /* If this is a control installation, increase the list size, if */ /* needed, and initialize the embedded client structure. If it is */ /* a removal, find the control in the list and remove it by sliding */ /* each subsequent structure down one element in array. */ client_name = (char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value; if (client_name == NULL) client_name = (char *) control_data->element_values[CONTROL_LABEL].parsed_value; if (install) { /* First see if this is an update to an already installed */ /* embedded client. If so, simply update the icon field */ for (i = 0; i < panel.embedded_client_count; i++) { if (strcmp (client_name, embedded_client_list[i].pchResName) == 0) { embedded_client_list[i].wControl = control_data->icon; break; } } if (i >= panel.embedded_client_count) { if (panel.embedded_client_count == panel.max_embedded_client_count) { panel.max_embedded_client_count += 10; embedded_client_list = (WmFpEmbeddedClientList) XtRealloc ((char *) embedded_client_list, sizeof (WmFpEmbeddedClientData) * panel.max_embedded_client_count); panel.embedded_client_list = (XtPointer) embedded_client_list; } embedded_client = &embedded_client_list[panel.embedded_client_count]; panel.embedded_client_count++; embedded_client->pchResName = XtNewString (client_name); embedded_client->wControl = control_data->icon; embedded_client->winParent = None; embedded_client->pCD = NULL; } for (i = 0; i < panel.embedded_client_count - 1; i++) { embedded_client = &embedded_client_list[i]; if (embedded_client->pCD != NULL) embedded_client->pCD->pECD = (void *) embedded_client; } } else { for (i = 0; i < panel.embedded_client_count; i++) { if (embedded_client_list[i].wControl == control_data->icon) { Position remove_y; Dimension adjust_y = 0; /* This block will reparent the client window, move it */ /* to a new window location, and remap the window. */ if (embedded_client_list[i].pCD != NULL) { client_window = embedded_client_list[i].pCD->client; UnManageWindow (embedded_client_list[i].pCD); XSync (XtDisplay (panel.shell), False); XMoveWindow (XtDisplay (panel.shell), client_window, 0, 0); XMapWindow (XtDisplay (panel.shell), client_window); } remove_y = embedded_client_list[i].y; /* deleted control height plus 5 pixels of form offset */ if(control_data->icon) { adjust_y = XtHeight (control_data->icon) + 5; } panel.embedded_client_count--; XtFree (embedded_client_list[i].pchResName); for (j = i; j < panel.embedded_client_count; j++) { embedded_client_list[j] = embedded_client_list[j + 1]; embedded_client = &embedded_client_list[j]; if (embedded_client_list[i].pCD != NULL) { embedded_client->pCD->pECD = (void *) embedded_client; if (control_data->icon && XtParent(control_data->icon) == XtParent(embedded_client->wControl) && remove_y < embedded_client->y) { embedded_client->y -= adjust_y; XMoveWindow(XtDisplay(panel.shell), embedded_client->pCD->client, embedded_client->x, embedded_client->y); } } } break; } } } /* Set the embedded client list and count into the window manager's */ /* screen global data. */ EmbeddedClientSetData (); } /************************************************************************ * * EmbeddedClientSetData * Set the embedded client list and count into the window manager's * screen global data. * ************************************************************************/ static void EmbeddedClientSetData (void) { WmScreenData *pSD; int i; /* Find the screen which contains the front panel and set it */ /* embedded client list and count. */ for (i = 0; i < wmGD.numScreens; i++) { pSD = &(wmGD.Screens[i]); if (pSD->managed) { if (pSD->wPanelist == panel.form) { pSD->pECD = (struct _WmFpEmbeddedClientData *) panel.embedded_client_list; pSD->numEmbeddedClients = panel.embedded_client_count; break; } } } } /************************************************************************ * * EmbeddedClientSetGeometry * Set the geometry and parenting window information for an * embedded client control. * * Inputs: embedded_client_data - a pointer to the structure containing * the embedded client information for a control. * * NOTE: Simplistic setting of position and size information. May need * to base on resolution and component parent. * ************************************************************************/ static void EmbeddedClientSetGeometry (WmFpEmbeddedClientData * embedded_client_data) { Widget control; control = embedded_client_data->wControl; embedded_client_data->winParent = XtWindow (XtParent (control)); embedded_client_data->x = XtX (control) + 3; embedded_client_data->y = XtY (control) + 3; embedded_client_data->width = XtWidth (control) - 6; embedded_client_data->height = XtHeight (control) - 6; } /************************************************************************ * * PushRecallRegister * This function adds a control to the list of push recall controls * and resets, if necessary, the Window Managers pointers to the list. * * Inputs: * control_data - the pointer to the ControlData * structure of * the control to be installed or removed. * * install - Boolean indicating whether to add or remove the control * from the push recall list. * ************************************************************************/ void PushRecallRegister (ControlData * control_data, Boolean install) { char * client_name; int i, j; WmFpPushRecallClientList push_recall_list = (WmFpPushRecallClientList) panel.push_recall_list; WmFpPushRecallClientData * push_recall = NULL; /* If this is a control installation, increase the list size, if */ /* needed, and initialize the push recall structure. If it is a */ /* removal, find the control in the push recall list and remove */ /* it by sliding each subsequent structure down one element in */ /* array. */ if (install) { client_name = (char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value; if (client_name == NULL) client_name = (char *) control_data->element_values[CONTROL_LABEL].parsed_value; /* First see if this is an update to an already installed */ /* push recall client. If so, simply update the icon field */ for (i = 0; i < panel.push_recall_count; i++) { if (strcmp (client_name, push_recall_list[i].pchResName) == 0) { push_recall_list[i].wControl = control_data->icon; break; } } if (i >= panel.push_recall_count) { if (panel.push_recall_count == panel.max_push_recall_count) { panel.max_push_recall_count += 10; push_recall_list = (WmFpPushRecallClientList) XtRealloc ((char *) push_recall_list, sizeof (WmFpPushRecallClientData) * panel.max_push_recall_count); panel.push_recall_list = (XtPointer) push_recall_list; } push_recall = &push_recall_list[panel.push_recall_count]; panel.push_recall_count++; push_recall->pchResName = XtNewString (client_name); push_recall->wControl = control_data->icon; push_recall->pCD = NULL; push_recall->tvTimeout.tv_sec = 0; } for (i = 0; i < panel.push_recall_count - 1; i++) { push_recall = &push_recall_list[i]; if (push_recall->pCD != NULL) push_recall->pCD->pPRCD = (void *) push_recall; } } else { for (i = 0; i < panel.push_recall_count; i++) { if (push_recall_list[i].wControl == control_data->icon) { panel.push_recall_count--; XtFree (push_recall_list[i].pchResName); for (j = i; j < panel.push_recall_count; j++) { push_recall_list[j] = push_recall_list[j + 1]; push_recall = &push_recall_list[j]; if (push_recall->pCD != NULL) push_recall->pCD->pPRCD = (void *) push_recall; } break; } } } /* Set the push recall list and count into the window manager's */ /* screen global data. */ PushRecallSetData (); } /************************************************************************ * * PushRecallSetData * Set the push recall list and count into the window manager's * screen global data. * ************************************************************************/ static void PushRecallSetData (void) { WmScreenData *pSD; int i; /* Find the screen which contains the front panel and set it */ /* push recall list and count. */ for (i = 0; i < wmGD.numScreens; i++) { pSD = &(wmGD.Screens[i]); if (pSD->managed) { if (pSD->wPanelist == panel.form) { pSD->pPRCD = (struct _WmFpPushRecallClientData *) panel.push_recall_list; pSD->numPushRecallClients = panel.push_recall_count; break; } } } } /************************************************************************ * * PushRecallGetData * Find the index within the push recall list of the entry which * contains the passed client name. * * Inputs: * client_name - contains the name of the push recall client to * be used for the lookup. * ************************************************************************/ int PushRecallGetData (char * client_name) { WmFpPushRecallClientList push_recall_list = (WmFpPushRecallClientList) panel.push_recall_list; int i; for (i = 0; i < panel.push_recall_count; i++) if (strcmp (client_name, push_recall_list[i].pchResName) == 0) return (i); /* Should never get here */ return 0; } /************************************************************************ * * WmPanelistWindowToSubpanel * Get a panel widget given its shell window. * ************************************************************************/ Widget WmPanelistWindowToSubpanel (Display *dpy, Window win) { Widget subpanel_shell; Widget * child_list; int num_children; Arg al[2]; int ac; /* Get the widget for the subpanel (Should be only child of the shell!) */ subpanel_shell = XtWindowToWidget (dpy, win); ac = 0; XtSetArg (al[ac], XmNchildren, &child_list); ac++; XtSetArg (al[ac], XmNnumChildren, &num_children); ac++; XtGetValues (subpanel_shell, al, ac); return ((num_children > 0) ? child_list[0] : (Widget)NULL); } /************************************************************************ * * WmPanelistSetBusy * Turn on or off the busy light. * ************************************************************************/ void WmFrontPanelSetBusy (Boolean on) { if (panel.busy_light_data != NULL) _DtControlSetBusy (panel.busy_light_data->icon, on); } /************************************************************************ * * SetGeometry * set x and y based on given geometry * ************************************************************************/ static void SetGeometry (Widget w, String geometry, Position * x, Position * y) { int x_return, y_return; unsigned int width_return, height_return; long flags; flags = XParseGeometry (geometry, &x_return, &y_return, &width_return, &height_return); if (flags) { if (flags & XValue) *x = (Position) x_return; if (flags & XNegative) *x = (Position) (WidthOfScreen (XtScreen (w)) - XtWidth(w)) + x_return; if (flags & YValue) *y = (Position) y_return; if (flags & YNegative) { *y = (Position) (HeightOfScreen (XtScreen (w)) - XtHeight(w)) + y_return; } if (flags & XValue || flags & YValue || flags & XNegative || flags & YNegative) { XtMoveWidget (w, *x, *y); } } } /************************************************************************ * * WmPanelistShow * ************************************************************************/ void WmPanelistShow (Widget w) { SwitchData * switch_data; Dimension switch_rc_height; Dimension switch_button_height; Dimension width = XtWidth(panel.shell); Dimension height = XtHeight(panel.shell); Position x = XtX(panel.shell); Position y = XtY(panel.shell); Dimension screen_width; Display * display; CompositeWidget cw; Widget * widget_list; DtWmHints vHints; String shell_geometry = NULL; char geometry_buffer[32]; XSizeHints hints; long supplied; int i; Arg al[20]; int ac; /* Find the switch data for later processing */ switch_data = NULL; for (i = 0; i < panel.box_data_count; i++) { if (panel.box_data[i]->switch_data != NULL) { switch_data = panel.box_data[i]->switch_data; break; } } /* Realize the shell so that it is sized properly for later */ /* positioning and child repositioning. */ XtRealizeWidget (panel.shell); /* See if a geometry has been set. */ ac = 0; XtSetArg (al[ac], XmNgeometry, &shell_geometry); ac++; XtGetValues (panel.shell, al, ac); /* If the shell has no default geometry, construct a default */ /* which will center the panel along the bottom of the display */ width = XtWidth (panel.shell); screen_width = WidthOfScreen (XtScreen (panel.shell)); display = XtDisplay (panel.shell); if (shell_geometry == NULL) { Position x; if (panel.element_values[PANEL_GEOMETRY].string_value != NULL) { shell_geometry = panel.element_values[PANEL_GEOMETRY].parsed_value; } else { x = (screen_width > width) ? (Position)(screen_width - width) / 2 : 0; snprintf (geometry_buffer, 32 - 1, "+%d-0", x); shell_geometry = geometry_buffer; } XtSetArg (al[0], XmNgeometry, shell_geometry); XtSetValues (panel.shell, al, 1); } /* Adjust the positions of the buttons within the switch */ /* so that they are spaced nicely. */ if (switch_data != NULL) { UpdateSwitchGeometry (switch_data->box_data); /* Reposition or adjust the front panel if it is either off */ /* the right edge of the screen or larger than the screen */ if (width > screen_width) { Arg al[1]; while (width > screen_width && panel.switch_row_count < switch_data->switch_count) { panel.switch_row_count++; XtSetArg (al[0], XmNnumColumns, panel.switch_row_count); XtSetValues (switch_data->rc, al, 1); width = XtWidth (panel.shell); } } } SetGeometry (panel.shell, shell_geometry, &x, &y); WorkspaceAdjustPanelPosition (x, y, XtWidth (panel.shell), XtHeight (panel.shell)); /* Set hints to avoid interactive placement */ if (XGetWMNormalHints(display, XtWindow(panel.shell), &hints, &supplied) != 0) { hints.flags |= USPosition|USSize; XSetWMNormalHints(display, XtWindow(panel.shell), &hints); } /* Set the shells icon and title for when it is minimized */ if (switch_data != NULL) { int current_workspace = switch_data->active_switch; XtSetArg (al[0], XmNiconName, switch_data->switch_names[current_workspace]); XtSetArg (al[1], XmNtitle, switch_data->switch_names[current_workspace]); XtSetValues (panel.shell, al, 2); } /* Set panel's window manager hints. */ vHints.flags = DtWM_HINTS_BEHAVIORS; vHints.behaviors = DtWM_BEHAVIOR_PANEL; _DtWsmSetDtWmHints (XtDisplay(panel.shell), XtWindow (panel.shell), &vHints); /* Set the subpanel's transientShell to update transientFor and */ /* Set the subpanel hints. */ vHints.behaviors |= DtWM_BEHAVIOR_SUBPANEL; vHints.flags |= DtWM_HINTS_ATTACH_WINDOW; vHints.attachWindow = XtWindow (panel.shell); for (i = 0, widget_list = M_PopupList (panel.shell); i < M_NumPopups (panel.shell); i++) { cw = (CompositeWidget) widget_list[i]; ac = 0; XtSetArg (al[ac], XmNtransientFor, NULL); ac++; XtSetValues ((Widget) cw, al, ac); ac = 0; XtSetArg (al[ac], XmNtransientFor, panel.shell); ac++; XtSetValues ((Widget) cw, al, ac); if (M_NumChildren (cw) > 0) { XtRealizeWidget ((M_Children (cw))[0]); _DtWsmSetDtWmHints (XtDisplay (panel.shell), XtWindow (widget_list[i]), &vHints); } } /* Set the push recall list and count into the window manager's */ /* screen global data. */ PushRecallSetData (); /* Set up the callback ot the workspace management API for */ /* catching changes in workspace configuration. */ DtWsmAddWorkspaceModifiedCallback(panel.shell, WorkspaceModifyCB, (XtPointer)switch_data); /* Get the front panel displayed */ XtSetMappedWhenManaged (panel.shell, True); XtPopup (panel.shell, XtGrabNone); /* Restore the session information */ SessionRestoreData (); /* Set up the window and geometry information for the embedded clients */ for (i = 0; i < panel.embedded_client_count; i++) EmbeddedClientSetGeometry (&(((WmFpEmbeddedClientList) panel.embedded_client_list)[i])); /* Set the embedded client list and count into the window manager's */ /* screen global data. */ EmbeddedClientSetData (); } /************************************************************************ * * WmPanelistAllocate * ************************************************************************/ Widget WmPanelistAllocate (Widget w, XtPointer global_data, XtPointer screen_data) { Boolean create_fp; panel.app_name = wmGD.mwmName; create_fp = FrontPanelReadDatabases (); if (create_fp) { #ifdef DT_PERFORMANCE _DtPerfChkpntMsgSend("Begin creating front panel"); #endif FrontPanelCreate (w); #ifdef DT_PERFORMANCE _DtPerfChkpntMsgSend("End creating front panel"); #endif panel.global_data = global_data; panel.screen_data = screen_data; return (panel.form); } else return(NULL); } /************************************************************************ * * WmSubpanelPosted * Add an event handler to catch when the subpanel is torn off. The * event handler will then change the subpanel's behavior to remain * displayed after a control is selected. * ************************************************************************/ void WmSubpanelPosted (Display * display, Window shell_window) { BoxData * box_data; ControlData * main_control_data; SubpanelData * subpanel_data; int i, j; /* Loop through the main controls to find the subpanel whose */ /* window matches the parameter shell window and then add the */ /* event handler for tear off behavoir. */ for (i = 0; i < panel.box_data_count; i++) { box_data = panel.box_data[i]; for (j = 0; j < box_data->control_data_count; j++) { main_control_data = box_data->control_data[j]; if (main_control_data->subpanel_data != NULL && XtWindow (main_control_data->subpanel_data->shell) == shell_window) { subpanel_data = main_control_data->subpanel_data; subpanel_data->posted_x = XtX (subpanel_data->shell); XtAddEventHandler (subpanel_data->shell, StructureNotifyMask, False, (XtEventHandler) SubpanelTornEventHandler, (XtPointer) main_control_data); break; } } } }