2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: WmFP.c /main/4 1995/11/01 11:36:41 rswiston $ */
24 /*****************************************************************************
30 * Description: This file contains functions used between the window manager
33 * (c) Copyright 1993, 1994 Hewlett-Packard Company
34 * (c) Copyright 1993, 1994 International Business Machines Corp.
35 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
36 * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
38 ****************************************************************************/
45 #include <Dt/DbReader.h>
46 #include <Dt/Control.h>
47 #include <Dt/ControlP.h>
48 #include <Dt/IconFile.h>
51 #include <Dt/MacrosP.h>
54 #include <Xm/ToggleBG.h>
55 #include <Xm/MwmUtil.h>
56 #include <Xm/AtomMgr.h>
57 #include <Xm/DrawingA.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/SeparatoG.h>
60 #include <Xm/DialogS.h>
62 #include <X11/Xatom.h>
63 #include <X11/keysymdef.h>
66 #include "DataBaseLoad.h"
78 extern void SubpanelTornEventHandler (Widget, XtPointer, XEvent *, Boolean *);
79 extern void WorkspaceModifyCB (Widget, Atom, int, XtPointer);
80 extern void SessionRestoreData (void);
81 extern void UnManageWindow (ClientData *pCD);
83 static void PushRecallSetData ();
84 static void EmbeddedClientSetData ();
85 static void EmbeddedClientSetGeometry (WmFpEmbeddedClientData *);
91 /************************************************************************
93 * EmbeddedClientReposition
94 * This function moves client windows within the main panel after
95 * controls have been resized.
97 * Inputs: icon - the icon of the embedded client to be repositioned
98 * x - the position of the resized control
99 * adjust - how much to move the window
101 ************************************************************************/
105 EmbeddedClientReposition (Widget icon,
112 WmFpEmbeddedClientList embedded_client_list =
113 (WmFpEmbeddedClientList) panel.embedded_client_list;
118 for (i = 0; i < panel.embedded_client_count; i++)
120 if (XtParent (icon) == XtParent (embedded_client_list[i].wControl) &&
121 embedded_client_list[i].x > x)
123 if (embedded_client_list[i].pCD != NULL)
125 embedded_client_list[i].x += adjust;
126 XMoveWindow (XtDisplay (panel.shell),
127 embedded_client_list[i].pCD->client,
128 embedded_client_list[i].x, embedded_client_list[i].y);
131 embedded_client_list[i].x += adjust;
139 /************************************************************************
141 * EmbeddedClientReparent
142 * This function sets of the data neccessary to call the window
143 * manager function which reparents an embedded client to a new
146 * Inputs: client_name - the name of the client to be reparented.
147 * icon - the widget that is to contain the client.
148 * parent_win - the parent win to reparent the client to.
150 ************************************************************************/
154 EmbeddedClientReparent (char * client_name,
159 WmFpEmbeddedClientList embedded_client_list =
160 (WmFpEmbeddedClientList) panel.embedded_client_list;
165 for (i = 0; i < panel.embedded_client_count; i++)
167 if (strcmp (client_name, embedded_client_list[i].pchResName) == 0)
172 /* Try to reparent the client to/from the main panel. If this */
173 /* fails, it is because of a dtwm restart and the clients have */
174 /* not yet been grabbed. So just reset the embedded client data */
176 if (ReparentEmbeddedClient (&embedded_client_list[i], icon,
177 XtWindow (XtParent (icon)),
178 XtX (icon) + 3, XtY (icon) + 3,
179 XtWidth(icon) - 6, XtHeight(icon) - 6) == False)
181 embedded_client_list[i].wControl = icon;
182 embedded_client_list[i].winParent = XtWindow (XtParent (icon));
183 embedded_client_list[i].x = XtX (icon) + 3;
184 embedded_client_list[i].y = XtY (icon) + 3;
185 embedded_client_list[i].width = XtWidth (icon) - 6;
186 embedded_client_list[i].height = XtHeight (icon) - 6;
193 /************************************************************************
195 * EmbeddedClientRegister
196 * This function adds a control to the list of embedded client controls
197 * and resets, if necessary, the Window Managers pointers to the list.
200 * control_data - the pointer to the ControlData * structure of
201 * the control to be installed or removed.
203 * install - Boolean indicating whether to add or remove the control
204 * from the push recall list.
206 ************************************************************************/
209 EmbeddedClientRegister (ControlData * control_data,
215 Window client_window;
218 WmFpEmbeddedClientList embedded_client_list =
219 (WmFpEmbeddedClientList) panel.embedded_client_list;
221 WmFpEmbeddedClientData * embedded_client = NULL;
223 if ((char) control_data->
224 element_values[CONTROL_TYPE].parsed_value != CONTROL_CLIENT)
228 /* If this is a control installation, increase the list size, if */
229 /* needed, and initialize the embedded client structure. If it is */
230 /* a removal, find the control in the list and remove it by sliding */
231 /* each subsequent structure down one element in array. */
233 client_name = (char *)
234 control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
236 if (client_name == NULL)
237 client_name = (char *)
238 control_data->element_values[CONTROL_LABEL].parsed_value;
243 /* First see if this is an update to an already installed */
244 /* embedded client. If so, simply update the icon field */
246 for (i = 0; i < panel.embedded_client_count; i++)
248 if (strcmp (client_name, embedded_client_list[i].pchResName) == 0)
250 embedded_client_list[i].wControl == control_data->icon;
255 if (i >= panel.embedded_client_count)
257 if (panel.embedded_client_count == panel.max_embedded_client_count)
259 panel.max_embedded_client_count += 10;
260 embedded_client_list = (WmFpEmbeddedClientList)
261 XtRealloc ((char *) embedded_client_list,
262 sizeof (WmFpEmbeddedClientData) *
263 panel.max_embedded_client_count);
264 panel.embedded_client_list = (XtPointer) embedded_client_list;
267 embedded_client = &embedded_client_list[panel.embedded_client_count];
268 panel.embedded_client_count++;
270 embedded_client->pchResName = XtNewString (client_name);
271 embedded_client->wControl = control_data->icon;
272 embedded_client->winParent = NULL;
273 embedded_client->pCD = NULL;
276 for (i = 0; i < panel.embedded_client_count - 1; i++)
278 embedded_client = &embedded_client_list[i];
279 if (embedded_client->pCD != NULL)
280 embedded_client->pCD->pECD = (void *) embedded_client;
285 for (i = 0; i < panel.embedded_client_count; i++)
287 if (embedded_client_list[i].wControl == control_data->icon)
293 /* This block will reparent the client window, move it */
294 /* to a new window location, and remap the window. */
296 if (embedded_client_list[i].pCD != NULL)
298 client_window = embedded_client_list[i].pCD->client;
299 UnManageWindow (embedded_client_list[i].pCD);
300 XSync (XtDisplay (panel.shell), False);
301 XMoveWindow (XtDisplay (panel.shell), client_window, 0, 0);
302 XMapWindow (XtDisplay (panel.shell), client_window);
305 remove_y = embedded_client_list[i].y;
308 /* deleted control height plus 5 pixels of form offset */
310 adjust_y = XtHeight (control_data->icon) + 5;
312 panel.embedded_client_count--;
314 XtFree (embedded_client_list[i].pchResName);
316 for (j = i; j < panel.embedded_client_count; j++)
318 embedded_client_list[j] = embedded_client_list[j + 1];
319 embedded_client = &embedded_client_list[j];
321 if (embedded_client_list[i].pCD != NULL)
323 embedded_client->pCD->pECD = (void *) embedded_client;
325 if (XtParent(control_data->icon) ==
326 XtParent(embedded_client->wControl) &&
327 remove_y < embedded_client->y)
329 embedded_client->y -= adjust_y;
330 XMoveWindow(XtDisplay(panel.shell),
331 embedded_client->pCD->client,
332 embedded_client->x, embedded_client->y);
343 /* Set the embedded client list and count into the window manager's */
344 /* screen global data. */
346 EmbeddedClientSetData ();
352 /************************************************************************
354 * EmbeddedClientSetData
355 * Set the embedded client list and count into the window manager's
356 * screen global data.
358 ************************************************************************/
361 EmbeddedClientSetData ()
368 /* Find the screen which contains the front panel and set it */
369 /* embedded client list and count. */
371 for (i = 0; i < wmGD.numScreens; i++)
373 pSD = &(wmGD.Screens[i]);
377 if (pSD->wPanelist == panel.form)
379 pSD->pECD = (struct _WmFpEmbeddedClientData *) panel.embedded_client_list;
380 pSD->numEmbeddedClients = panel.embedded_client_count;
390 /************************************************************************
392 * EmbeddedClientSetGeometry
393 * Set the geometry and parenting window information for an
394 * embedded client control.
396 * Inputs: embedded_client_data - a pointer to the structure containing
397 * the embedded client information for a control.
399 * NOTE: Simplistic setting of position and size information. May need
400 * to base on resolution and component parent.
402 ************************************************************************/
405 EmbeddedClientSetGeometry (WmFpEmbeddedClientData * embedded_client_data)
411 control = embedded_client_data->wControl;
413 embedded_client_data->winParent = XtWindow (XtParent (control));
416 embedded_client_data->x = XtX (control) + 3;
417 embedded_client_data->y = XtY (control) + 3;
418 embedded_client_data->width = XtWidth (control) - 6;
419 embedded_client_data->height = XtHeight (control) - 6;
425 /************************************************************************
428 * This function adds a control to the list of push recall controls
429 * and resets, if necessary, the Window Managers pointers to the list.
432 * control_data - the pointer to the ControlData * structure of
433 * the control to be installed or removed.
435 * install - Boolean indicating whether to add or remove the control
436 * from the push recall list.
438 ************************************************************************/
441 PushRecallRegister (ControlData * control_data,
449 WmFpPushRecallClientList push_recall_list =
450 (WmFpPushRecallClientList) panel.push_recall_list;
452 WmFpPushRecallClientData * push_recall = NULL;
455 /* If this is a control installation, increase the list size, if */
456 /* needed, and initialize the push recall structure. If it is a */
457 /* removal, find the control in the push recall list and remove */
458 /* it by sliding each subsequent structure down one element in */
463 client_name = (char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
465 if (client_name == NULL)
466 client_name = (char *) control_data->element_values[CONTROL_LABEL].parsed_value;
469 /* First see if this is an update to an already installed */
470 /* push recall client. If so, simply update the icon field */
472 for (i = 0; i < panel.push_recall_count; i++)
474 if (strcmp (client_name, push_recall_list[i].pchResName) == 0)
476 push_recall_list[i].wControl == control_data->icon;
481 if (i >= panel.push_recall_count)
483 if (panel.push_recall_count == panel.max_push_recall_count)
485 panel.max_push_recall_count += 10;
486 push_recall_list = (WmFpPushRecallClientList)
487 XtRealloc ((char *) push_recall_list,
488 sizeof (WmFpPushRecallClientData) *
489 panel.max_push_recall_count);
490 panel.push_recall_list = (XtPointer) push_recall_list;
493 push_recall = &push_recall_list[panel.push_recall_count];
494 panel.push_recall_count++;
496 push_recall->pchResName = XtNewString (client_name);
497 push_recall->wControl = control_data->icon;
498 push_recall->pCD = NULL;
499 push_recall->tvTimeout.tv_sec = 0;
502 for (i = 0; i < panel.push_recall_count - 1; i++)
504 push_recall = &push_recall_list[i];
505 if (push_recall->pCD != NULL)
506 push_recall->pCD->pPRCD = (void *) push_recall;
511 for (i = 0; i < panel.push_recall_count; i++)
513 if (push_recall_list[i].wControl == control_data->icon)
515 panel.push_recall_count--;
517 XtFree (push_recall_list[i].pchResName);
519 for (j = i; j < panel.push_recall_count; j++)
521 push_recall_list[j] = push_recall_list[j + 1];
522 push_recall = &push_recall_list[j];
524 if (push_recall->pCD != NULL)
525 push_recall->pCD->pPRCD = (void *) push_recall;
534 /* Set the push recall list and count into the window manager's */
535 /* screen global data. */
537 PushRecallSetData ();
543 /************************************************************************
546 * Set the push recall list and count into the window manager's
547 * screen global data.
549 ************************************************************************/
559 /* Find the screen which contains the front panel and set it */
560 /* push recall list and count. */
562 for (i = 0; i < wmGD.numScreens; i++)
564 pSD = &(wmGD.Screens[i]);
568 if (pSD->wPanelist == panel.form)
570 pSD->pPRCD = (struct _WmFpPushRecallClientData *) panel.push_recall_list;
571 pSD->numPushRecallClients = panel.push_recall_count;
581 /************************************************************************
584 * Find the index within the push recall list of the entry which
585 * contains the passed client name.
588 * client_name - contains the name of the push recall client to
589 * be used for the lookup.
591 ************************************************************************/
595 PushRecallGetData (char * client_name)
599 WmFpPushRecallClientList push_recall_list =
600 (WmFpPushRecallClientList) panel.push_recall_list;
603 for (i = 0; i < panel.push_recall_count; i++)
604 if (strcmp (client_name, push_recall_list[i].pchResName) == 0)
611 /************************************************************************
613 * WmPanelistWindowToSubpanel
614 * Get a panel widget given its shell window.
616 ************************************************************************/
619 WmPanelistWindowToSubpanel (Display *dpy, Window win)
622 Widget subpanel_shell;
630 /* Get the widget for the subpanel (Should be only child of the shell!) */
632 subpanel_shell = XtWindowToWidget (dpy, win);
635 XtSetArg (al[ac], XmNchildren, &child_list); ac++;
636 XtSetArg (al[ac], XmNnumChildren, &num_children); ac++;
637 XtGetValues (subpanel_shell, al, ac);
639 return ((num_children > 0) ? child_list[0] : (Widget)NULL);
645 /************************************************************************
648 * Turn on or off the busy light.
650 ************************************************************************/
653 WmFrontPanelSetBusy (Boolean on)
656 if (panel.busy_light_data != NULL)
657 _DtControlSetBusy (panel.busy_light_data->icon, on);
663 /************************************************************************
666 * set x and y based on given geometry
668 ************************************************************************/
671 SetGeometry (Widget w, String geometry, Position * x, Position * y)
674 int x_return, y_return;
675 unsigned int width_return, height_return;
678 flags = XParseGeometry (geometry, &x_return, &y_return,
679 &width_return, &height_return);
684 *x = (Position) x_return;
686 if (flags & XNegative)
687 *x = (Position) (WidthOfScreen (XtScreen (w)) - XtWidth(w))
691 *y = (Position) y_return;
693 if (flags & YNegative)
695 *y = (Position) (HeightOfScreen (XtScreen (w)) - XtHeight(w))
699 if (flags & XValue || flags & YValue || flags & XNegative ||
702 XtMoveWidget (w, *x, *y);
709 /************************************************************************
713 ************************************************************************/
716 WmPanelistShow (Widget w)
719 SwitchData * switch_data;
720 Dimension switch_rc_height;
721 Dimension switch_button_height;
723 Dimension width = XtWidth(panel.shell);
724 Dimension height = XtHeight(panel.shell);
725 Position x = XtX(panel.shell);
726 Position y = XtY(panel.shell);
727 Dimension screen_width;
732 Widget * widget_list;
735 String shell_geometry = NULL;
736 char geometry_buffer[32];
747 /* Find the switch data for later processing */
751 for (i = 0; i < panel.box_data_count; i++)
753 if (panel.box_data[i]->switch_data != NULL)
755 switch_data = panel.box_data[i]->switch_data;
761 /* Realize the shell so that it is sized properly for later */
762 /* positioning and child repositioning. */
764 XtRealizeWidget (panel.shell);
767 /* See if a geometry has been set. */
770 XtSetArg (al[ac], XmNgeometry, &shell_geometry); ac++;
771 XtGetValues (panel.shell, al, ac);
774 /* If the shell has no default geometry, construct a default */
775 /* which will center the panel along the bottom of the display */
777 width = XtWidth (panel.shell);
778 screen_width = WidthOfScreen (XtScreen (panel.shell));
779 display = XtDisplay (panel.shell);
781 if (shell_geometry == NULL)
784 char geometry_buffer[32];
786 if (panel.element_values[PANEL_GEOMETRY].string_value != NULL)
788 shell_geometry = panel.element_values[PANEL_GEOMETRY].parsed_value;
792 x = (screen_width > width) ? (Position)(screen_width - width) / 2 : 0;
793 sprintf (geometry_buffer, "+%d-0", x);
794 shell_geometry = geometry_buffer;
797 XtSetArg (al[0], XmNgeometry, shell_geometry);
798 XtSetValues (panel.shell, al, 1);
802 /* Adjust the positions of the buttons within the switch */
803 /* so that they are spaced nicely. */
805 if (switch_data != NULL)
807 UpdateSwitchGeometry (switch_data->box_data);
810 /* Reposition or adjust the front panel if it is either off */
811 /* the right edge of the screen or larger than the screen */
813 if (width > screen_width)
817 while (width > screen_width &&
818 panel.switch_row_count < switch_data->switch_count)
820 panel.switch_row_count++;
822 XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
823 XtSetValues (switch_data->rc, al, 1);
825 width = XtWidth (panel.shell);
830 SetGeometry (panel.shell, shell_geometry, &x, &y);
831 WorkspaceAdjustPanelPosition (x, y, XtWidth (panel.shell),
832 XtHeight (panel.shell));
835 /* Set hints to avoid interactive placement */
837 if (XGetWMNormalHints(display, XtWindow(panel.shell),
838 &hints, &supplied) != 0)
840 hints.flags |= USPosition|USSize;
841 XSetWMNormalHints(display, XtWindow(panel.shell), &hints);
845 /* Set the shells icon and title for when it is minimized */
847 if (switch_data != NULL)
849 int current_workspace = switch_data->active_switch;
851 XtSetArg (al[0], XmNiconName, switch_data->switch_names[current_workspace]);
852 XtSetArg (al[1], XmNtitle, switch_data->switch_names[current_workspace]);
853 XtSetValues (panel.shell, al, 2);
857 /* Set panel's window manager hints. */
859 vHints.flags = DtWM_HINTS_BEHAVIORS;
860 vHints.behaviors = DtWM_BEHAVIOR_PANEL;
861 _DtWsmSetDtWmHints (XtDisplay(panel.shell), XtWindow (panel.shell), &vHints);
864 /* Set the subpanel's transientShell to update transientFor and */
865 /* Set the subpanel hints. */
867 vHints.behaviors |= DtWM_BEHAVIOR_SUBPANEL;
868 vHints.flags |= DtWM_HINTS_ATTACH_WINDOW;
869 vHints.attachWindow = XtWindow (panel.shell);
871 for (i = 0, widget_list = M_PopupList (panel.shell);
872 i < M_NumPopups (panel.shell); i++)
874 cw = (CompositeWidget) widget_list[i];
877 XtSetArg (al[ac], XmNtransientFor, NULL); ac++;
878 XtSetValues ((Widget) cw, al, ac);
881 XtSetArg (al[ac], XmNtransientFor, panel.shell); ac++;
882 XtSetValues ((Widget) cw, al, ac);
884 if (M_NumChildren (cw) > 0)
886 XtRealizeWidget ((M_Children (cw))[0]);
887 _DtWsmSetDtWmHints (XtDisplay (panel.shell),
888 XtWindow (widget_list[i]), &vHints);
893 /* Set the push recall list and count into the window manager's */
894 /* screen global data. */
896 PushRecallSetData ();
899 /* Set up the callback ot the workspace management API for */
900 /* catching changes in workspace configuration. */
902 DtWsmAddWorkspaceModifiedCallback(panel.shell,
903 WorkspaceModifyCB, (XtPointer)switch_data);
906 /* Get the front panel displayed */
908 XtSetMappedWhenManaged (panel.shell, True);
909 XtPopup (panel.shell, XtGrabNone);
912 /* Restore the session information */
914 SessionRestoreData ();
917 /* Set up the window and geometry information for the embedded clients */
919 for (i = 0; i < panel.embedded_client_count; i++)
920 EmbeddedClientSetGeometry (&(((WmFpEmbeddedClientList) panel.embedded_client_list)[i]));
923 /* Set the embedded client list and count into the window manager's */
924 /* screen global data. */
926 EmbeddedClientSetData ();
932 /************************************************************************
936 ************************************************************************/
939 WmPanelistAllocate (Widget w,
940 XtPointer global_data,
941 XtPointer screen_data)
946 panel.app_name = wmGD.mwmName;
947 create_fp = FrontPanelReadDatabases ();
951 #ifdef DT_PERFORMANCE
952 _DtPerfChkpntMsgSend("Begin creating front panel");
955 FrontPanelCreate (w);
957 #ifdef DT_PERFORMANCE
958 _DtPerfChkpntMsgSend("End creating front panel");
961 panel.global_data = global_data;
962 panel.screen_data = screen_data;
973 /************************************************************************
976 * Add an event handler to catch when the subpanel is torn off. The
977 * event handler will then change the subpanel's behavior to remain
978 * displayed after a control is selected.
980 ************************************************************************/
983 WmSubpanelPosted (Display * display,
988 ControlData * main_control_data;
989 SubpanelData * subpanel_data;
994 /* Loop through the main controls to find the subpanel whose */
995 /* window matches the parameter shell window and then add the */
996 /* event handler for tear off behavoir. */
998 for (i = 0; i < panel.box_data_count; i++)
1000 box_data = panel.box_data[i];
1002 for (j = 0; j < box_data->control_data_count; j++)
1004 main_control_data = box_data->control_data[j];
1006 if (main_control_data->subpanel_data != NULL &&
1007 XtWindow (main_control_data->subpanel_data->shell) == shell_window)
1009 subpanel_data = main_control_data->subpanel_data;
1011 subpanel_data->posted_x = XtX (subpanel_data->shell);
1013 XtAddEventHandler (subpanel_data->shell, StructureNotifyMask, False,
1014 (XtEventHandler) SubpanelTornEventHandler,
1015 (XtPointer) main_control_data);