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"
77 extern void SubpanelTornEventHandler (Widget, XtPointer, XEvent *, Boolean *);
78 extern void WorkspaceModifyCB (Widget, Atom, int, XtPointer);
79 extern void SessionRestoreData (void);
80 extern void UnManageWindow (ClientData *pCD);
82 static void PushRecallSetData ();
83 static void EmbeddedClientSetData ();
84 static void EmbeddedClientSetGeometry (WmFpEmbeddedClientData *);
90 /************************************************************************
92 * EmbeddedClientReposition
93 * This function moves client windows within the main panel after
94 * controls have been resized.
96 * Inputs: icon - the icon of the embedded client to be repositioned
97 * x - the position of the resized control
98 * adjust - how much to move the window
100 ************************************************************************/
104 EmbeddedClientReposition (Widget icon,
111 WmFpEmbeddedClientList embedded_client_list =
112 (WmFpEmbeddedClientList) panel.embedded_client_list;
117 for (i = 0; i < panel.embedded_client_count; i++)
119 if (XtParent (icon) == XtParent (embedded_client_list[i].wControl) &&
120 embedded_client_list[i].x > x)
122 if (embedded_client_list[i].pCD != NULL)
124 embedded_client_list[i].x += adjust;
125 XMoveWindow (XtDisplay (panel.shell),
126 embedded_client_list[i].pCD->client,
127 embedded_client_list[i].x, embedded_client_list[i].y);
130 embedded_client_list[i].x += adjust;
138 /************************************************************************
140 * EmbeddedClientReparent
141 * This function sets of the data neccessary to call the window
142 * manager function which reparents an embedded client to a new
145 * Inputs: client_name - the name of the client to be reparented.
146 * icon - the widget that is to contain the client.
147 * parent_win - the parent win to reparent the client to.
149 ************************************************************************/
153 EmbeddedClientReparent (char * client_name,
158 WmFpEmbeddedClientList embedded_client_list =
159 (WmFpEmbeddedClientList) panel.embedded_client_list;
164 for (i = 0; i < panel.embedded_client_count; i++)
166 if (strcmp (client_name, embedded_client_list[i].pchResName) == 0)
171 /* Try to reparent the client to/from the main panel. If this */
172 /* fails, it is because of a dtwm restart and the clients have */
173 /* not yet been grabbed. So just reset the embedded client data */
175 if (ReparentEmbeddedClient (&embedded_client_list[i], icon,
176 XtWindow (XtParent (icon)),
177 XtX (icon) + 3, XtY (icon) + 3,
178 XtWidth(icon) - 6, XtHeight(icon) - 6) == False)
180 embedded_client_list[i].wControl = icon;
181 embedded_client_list[i].winParent = XtWindow (XtParent (icon));
182 embedded_client_list[i].x = XtX (icon) + 3;
183 embedded_client_list[i].y = XtY (icon) + 3;
184 embedded_client_list[i].width = XtWidth (icon) - 6;
185 embedded_client_list[i].height = XtHeight (icon) - 6;
192 /************************************************************************
194 * EmbeddedClientRegister
195 * This function adds a control to the list of embedded client controls
196 * and resets, if necessary, the Window Managers pointers to the list.
199 * control_data - the pointer to the ControlData * structure of
200 * the control to be installed or removed.
202 * install - Boolean indicating whether to add or remove the control
203 * from the push recall list.
205 ************************************************************************/
208 EmbeddedClientRegister (ControlData * control_data,
214 Window client_window;
217 WmFpEmbeddedClientList embedded_client_list =
218 (WmFpEmbeddedClientList) panel.embedded_client_list;
220 WmFpEmbeddedClientData * embedded_client = NULL;
222 if ((char) control_data->
223 element_values[CONTROL_TYPE].parsed_value != CONTROL_CLIENT)
227 /* If this is a control installation, increase the list size, if */
228 /* needed, and initialize the embedded client structure. If it is */
229 /* a removal, find the control in the list and remove it by sliding */
230 /* each subsequent structure down one element in array. */
232 client_name = (char *)
233 control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
235 if (client_name == NULL)
236 client_name = (char *)
237 control_data->element_values[CONTROL_LABEL].parsed_value;
242 /* First see if this is an update to an already installed */
243 /* embedded client. If so, simply update the icon field */
245 for (i = 0; i < panel.embedded_client_count; i++)
247 if (strcmp (client_name, embedded_client_list[i].pchResName) == 0)
249 embedded_client_list[i].wControl == control_data->icon;
254 if (i >= panel.embedded_client_count)
256 if (panel.embedded_client_count == panel.max_embedded_client_count)
258 panel.max_embedded_client_count += 10;
259 embedded_client_list = (WmFpEmbeddedClientList)
260 XtRealloc ((char *) embedded_client_list,
261 sizeof (WmFpEmbeddedClientData) *
262 panel.max_embedded_client_count);
263 panel.embedded_client_list = (XtPointer) embedded_client_list;
266 embedded_client = &embedded_client_list[panel.embedded_client_count];
267 panel.embedded_client_count++;
269 embedded_client->pchResName = XtNewString (client_name);
270 embedded_client->wControl = control_data->icon;
271 embedded_client->winParent = NULL;
272 embedded_client->pCD = NULL;
275 for (i = 0; i < panel.embedded_client_count - 1; i++)
277 embedded_client = &embedded_client_list[i];
278 if (embedded_client->pCD != NULL)
279 embedded_client->pCD->pECD = (void *) embedded_client;
284 for (i = 0; i < panel.embedded_client_count; i++)
286 if (embedded_client_list[i].wControl == control_data->icon)
292 /* This block will reparent the client window, move it */
293 /* to a new window location, and remap the window. */
295 if (embedded_client_list[i].pCD != NULL)
297 client_window = embedded_client_list[i].pCD->client;
298 UnManageWindow (embedded_client_list[i].pCD);
299 XSync (XtDisplay (panel.shell), False);
300 XMoveWindow (XtDisplay (panel.shell), client_window, 0, 0);
301 XMapWindow (XtDisplay (panel.shell), client_window);
304 remove_y = embedded_client_list[i].y;
307 /* deleted control height plus 5 pixels of form offset */
309 adjust_y = XtHeight (control_data->icon) + 5;
311 panel.embedded_client_count--;
313 XtFree (embedded_client_list[i].pchResName);
315 for (j = i; j < panel.embedded_client_count; j++)
317 embedded_client_list[j] = embedded_client_list[j + 1];
318 embedded_client = &embedded_client_list[j];
320 if (embedded_client_list[i].pCD != NULL)
322 embedded_client->pCD->pECD = (void *) embedded_client;
324 if (XtParent(control_data->icon) ==
325 XtParent(embedded_client->wControl) &&
326 remove_y < embedded_client->y)
328 embedded_client->y -= adjust_y;
329 XMoveWindow(XtDisplay(panel.shell),
330 embedded_client->pCD->client,
331 embedded_client->x, embedded_client->y);
342 /* Set the embedded client list and count into the window manager's */
343 /* screen global data. */
345 EmbeddedClientSetData ();
351 /************************************************************************
353 * EmbeddedClientSetData
354 * Set the embedded client list and count into the window manager's
355 * screen global data.
357 ************************************************************************/
360 EmbeddedClientSetData ()
367 /* Find the screen which contains the front panel and set it */
368 /* embedded client list and count. */
370 for (i = 0; i < wmGD.numScreens; i++)
372 pSD = &(wmGD.Screens[i]);
376 if (pSD->wPanelist == panel.form)
378 pSD->pECD = (struct _WmFpEmbeddedClientData *) panel.embedded_client_list;
379 pSD->numEmbeddedClients = panel.embedded_client_count;
389 /************************************************************************
391 * EmbeddedClientSetGeometry
392 * Set the geometry and parenting window information for an
393 * embedded client control.
395 * Inputs: embedded_client_data - a pointer to the structure containing
396 * the embedded client information for a control.
398 * NOTE: Simplistic setting of position and size information. May need
399 * to base on resolution and component parent.
401 ************************************************************************/
404 EmbeddedClientSetGeometry (WmFpEmbeddedClientData * embedded_client_data)
410 control = embedded_client_data->wControl;
412 embedded_client_data->winParent = XtWindow (XtParent (control));
415 embedded_client_data->x = XtX (control) + 3;
416 embedded_client_data->y = XtY (control) + 3;
417 embedded_client_data->width = XtWidth (control) - 6;
418 embedded_client_data->height = XtHeight (control) - 6;
424 /************************************************************************
427 * This function adds a control to the list of push recall controls
428 * and resets, if necessary, the Window Managers pointers to the list.
431 * control_data - the pointer to the ControlData * structure of
432 * the control to be installed or removed.
434 * install - Boolean indicating whether to add or remove the control
435 * from the push recall list.
437 ************************************************************************/
440 PushRecallRegister (ControlData * control_data,
448 WmFpPushRecallClientList push_recall_list =
449 (WmFpPushRecallClientList) panel.push_recall_list;
451 WmFpPushRecallClientData * push_recall = NULL;
454 /* If this is a control installation, increase the list size, if */
455 /* needed, and initialize the push recall structure. If it is a */
456 /* removal, find the control in the push recall list and remove */
457 /* it by sliding each subsequent structure down one element in */
462 client_name = (char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
464 if (client_name == NULL)
465 client_name = (char *) control_data->element_values[CONTROL_LABEL].parsed_value;
468 /* First see if this is an update to an already installed */
469 /* push recall client. If so, simply update the icon field */
471 for (i = 0; i < panel.push_recall_count; i++)
473 if (strcmp (client_name, push_recall_list[i].pchResName) == 0)
475 push_recall_list[i].wControl == control_data->icon;
480 if (i >= panel.push_recall_count)
482 if (panel.push_recall_count == panel.max_push_recall_count)
484 panel.max_push_recall_count += 10;
485 push_recall_list = (WmFpPushRecallClientList)
486 XtRealloc ((char *) push_recall_list,
487 sizeof (WmFpPushRecallClientData) *
488 panel.max_push_recall_count);
489 panel.push_recall_list = (XtPointer) push_recall_list;
492 push_recall = &push_recall_list[panel.push_recall_count];
493 panel.push_recall_count++;
495 push_recall->pchResName = XtNewString (client_name);
496 push_recall->wControl = control_data->icon;
497 push_recall->pCD = NULL;
498 push_recall->tvTimeout.tv_sec = 0;
501 for (i = 0; i < panel.push_recall_count - 1; i++)
503 push_recall = &push_recall_list[i];
504 if (push_recall->pCD != NULL)
505 push_recall->pCD->pPRCD = (void *) push_recall;
510 for (i = 0; i < panel.push_recall_count; i++)
512 if (push_recall_list[i].wControl == control_data->icon)
514 panel.push_recall_count--;
516 XtFree (push_recall_list[i].pchResName);
518 for (j = i; j < panel.push_recall_count; j++)
520 push_recall_list[j] = push_recall_list[j + 1];
521 push_recall = &push_recall_list[j];
523 if (push_recall->pCD != NULL)
524 push_recall->pCD->pPRCD = (void *) push_recall;
533 /* Set the push recall list and count into the window manager's */
534 /* screen global data. */
536 PushRecallSetData ();
542 /************************************************************************
545 * Set the push recall list and count into the window manager's
546 * screen global data.
548 ************************************************************************/
558 /* Find the screen which contains the front panel and set it */
559 /* push recall list and count. */
561 for (i = 0; i < wmGD.numScreens; i++)
563 pSD = &(wmGD.Screens[i]);
567 if (pSD->wPanelist == panel.form)
569 pSD->pPRCD = (struct _WmFpPushRecallClientData *) panel.push_recall_list;
570 pSD->numPushRecallClients = panel.push_recall_count;
580 /************************************************************************
583 * Find the index within the push recall list of the entry which
584 * contains the passed client name.
587 * client_name - contains the name of the push recall client to
588 * be used for the lookup.
590 ************************************************************************/
594 PushRecallGetData (char * client_name)
598 WmFpPushRecallClientList push_recall_list =
599 (WmFpPushRecallClientList) panel.push_recall_list;
602 for (i = 0; i < panel.push_recall_count; i++)
603 if (strcmp (client_name, push_recall_list[i].pchResName) == 0)
610 /************************************************************************
612 * WmPanelistWindowToSubpanel
613 * Get a panel widget given its shell window.
615 ************************************************************************/
618 WmPanelistWindowToSubpanel (Display *dpy, Window win)
621 Widget subpanel_shell;
629 /* Get the widget for the subpanel (Should be only child of the shell!) */
631 subpanel_shell = XtWindowToWidget (dpy, win);
634 XtSetArg (al[ac], XmNchildren, &child_list); ac++;
635 XtSetArg (al[ac], XmNnumChildren, &num_children); ac++;
636 XtGetValues (subpanel_shell, al, ac);
638 return ((num_children > 0) ? child_list[0] : (Widget)NULL);
644 /************************************************************************
647 * Turn on or off the busy light.
649 ************************************************************************/
652 WmFrontPanelSetBusy (Boolean on)
655 if (panel.busy_light_data != NULL)
656 _DtControlSetBusy (panel.busy_light_data->icon, on);
662 /************************************************************************
665 * set x and y based on given geometry
667 ************************************************************************/
670 SetGeometry (Widget w, String geometry, Position * x, Position * y)
673 int x_return, y_return;
674 unsigned int width_return, height_return;
677 flags = XParseGeometry (geometry, &x_return, &y_return,
678 &width_return, &height_return);
683 *x = (Position) x_return;
685 if (flags & XNegative)
686 *x = (Position) (WidthOfScreen (XtScreen (w)) - XtWidth(w))
690 *y = (Position) y_return;
692 if (flags & YNegative)
694 *y = (Position) (HeightOfScreen (XtScreen (w)) - XtHeight(w))
698 if (flags & XValue || flags & YValue || flags & XNegative ||
701 XtMoveWidget (w, *x, *y);
708 /************************************************************************
712 ************************************************************************/
715 WmPanelistShow (Widget w)
718 SwitchData * switch_data;
719 Dimension switch_rc_height;
720 Dimension switch_button_height;
722 Dimension width = XtWidth(panel.shell);
723 Dimension height = XtHeight(panel.shell);
724 Position x = XtX(panel.shell);
725 Position y = XtY(panel.shell);
726 Dimension screen_width;
731 Widget * widget_list;
734 String shell_geometry = NULL;
735 char geometry_buffer[32];
746 /* Find the switch data for later processing */
750 for (i = 0; i < panel.box_data_count; i++)
752 if (panel.box_data[i]->switch_data != NULL)
754 switch_data = panel.box_data[i]->switch_data;
760 /* Realize the shell so that it is sized properly for later */
761 /* positioning and child repositioning. */
763 XtRealizeWidget (panel.shell);
766 /* See if a geometry has been set. */
769 XtSetArg (al[ac], XmNgeometry, &shell_geometry); ac++;
770 XtGetValues (panel.shell, al, ac);
773 /* If the shell has no default geometry, construct a default */
774 /* which will center the panel along the bottom of the display */
776 width = XtWidth (panel.shell);
777 screen_width = WidthOfScreen (XtScreen (panel.shell));
778 display = XtDisplay (panel.shell);
780 if (shell_geometry == NULL)
783 char geometry_buffer[32];
785 if (panel.element_values[PANEL_GEOMETRY].string_value != NULL)
787 shell_geometry = panel.element_values[PANEL_GEOMETRY].parsed_value;
791 x = (screen_width > width) ? (Position)(screen_width - width) / 2 : 0;
792 sprintf (geometry_buffer, "+%d-0", x);
793 shell_geometry = geometry_buffer;
796 XtSetArg (al[0], XmNgeometry, shell_geometry);
797 XtSetValues (panel.shell, al, 1);
801 /* Adjust the positions of the buttons within the switch */
802 /* so that they are spaced nicely. */
804 if (switch_data != NULL)
806 UpdateSwitchGeometry (switch_data->box_data);
809 /* Reposition or adjust the front panel if it is either off */
810 /* the right edge of the screen or larger than the screen */
812 if (width > screen_width)
816 while (width > screen_width &&
817 panel.switch_row_count < switch_data->switch_count)
819 panel.switch_row_count++;
821 XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
822 XtSetValues (switch_data->rc, al, 1);
824 width = XtWidth (panel.shell);
829 SetGeometry (panel.shell, shell_geometry, &x, &y);
830 WorkspaceAdjustPanelPosition (x, y, XtWidth (panel.shell),
831 XtHeight (panel.shell));
834 /* Set hints to avoid interactive placement */
836 if (XGetWMNormalHints(display, XtWindow(panel.shell),
837 &hints, &supplied) != 0)
839 hints.flags |= USPosition|USSize;
840 XSetWMNormalHints(display, XtWindow(panel.shell), &hints);
844 /* Set the shells icon and title for when it is minimized */
846 if (switch_data != NULL)
848 int current_workspace = switch_data->active_switch;
850 XtSetArg (al[0], XmNiconName, switch_data->switch_names[current_workspace]);
851 XtSetArg (al[1], XmNtitle, switch_data->switch_names[current_workspace]);
852 XtSetValues (panel.shell, al, 2);
856 /* Set panel's window manager hints. */
858 vHints.flags = DtWM_HINTS_BEHAVIORS;
859 vHints.behaviors = DtWM_BEHAVIOR_PANEL;
860 _DtWsmSetDtWmHints (XtDisplay(panel.shell), XtWindow (panel.shell), &vHints);
863 /* Set the subpanel's transientShell to update transientFor and */
864 /* Set the subpanel hints. */
866 vHints.behaviors |= DtWM_BEHAVIOR_SUBPANEL;
867 vHints.flags |= DtWM_HINTS_ATTACH_WINDOW;
868 vHints.attachWindow = XtWindow (panel.shell);
870 for (i = 0, widget_list = M_PopupList (panel.shell);
871 i < M_NumPopups (panel.shell); i++)
873 cw = (CompositeWidget) widget_list[i];
876 XtSetArg (al[ac], XmNtransientFor, NULL); ac++;
877 XtSetValues ((Widget) cw, al, ac);
880 XtSetArg (al[ac], XmNtransientFor, panel.shell); ac++;
881 XtSetValues ((Widget) cw, al, ac);
883 if (M_NumChildren (cw) > 0)
885 XtRealizeWidget ((M_Children (cw))[0]);
886 _DtWsmSetDtWmHints (XtDisplay (panel.shell),
887 XtWindow (widget_list[i]), &vHints);
892 /* Set the push recall list and count into the window manager's */
893 /* screen global data. */
895 PushRecallSetData ();
898 /* Set up the callback ot the workspace management API for */
899 /* catching changes in workspace configuration. */
901 DtWsmAddWorkspaceModifiedCallback(panel.shell,
902 WorkspaceModifyCB, (XtPointer)switch_data);
905 /* Get the front panel displayed */
907 XtSetMappedWhenManaged (panel.shell, True);
908 XtPopup (panel.shell, XtGrabNone);
911 /* Restore the session information */
913 SessionRestoreData ();
916 /* Set up the window and geometry information for the embedded clients */
918 for (i = 0; i < panel.embedded_client_count; i++)
919 EmbeddedClientSetGeometry (&(((WmFpEmbeddedClientList) panel.embedded_client_list)[i]));
922 /* Set the embedded client list and count into the window manager's */
923 /* screen global data. */
925 EmbeddedClientSetData ();
931 /************************************************************************
935 ************************************************************************/
938 WmPanelistAllocate (Widget w,
939 XtPointer global_data,
940 XtPointer screen_data)
945 panel.app_name = wmGD.mwmName;
946 create_fp = FrontPanelReadDatabases ();
950 #ifdef DT_PERFORMANCE
951 _DtPerfChkpntMsgSend("Begin creating front panel");
954 FrontPanelCreate (w);
956 #ifdef DT_PERFORMANCE
957 _DtPerfChkpntMsgSend("End creating front panel");
960 panel.global_data = global_data;
961 panel.screen_data = screen_data;
972 /************************************************************************
975 * Add an event handler to catch when the subpanel is torn off. The
976 * event handler will then change the subpanel's behavior to remain
977 * displayed after a control is selected.
979 ************************************************************************/
982 WmSubpanelPosted (Display * display,
987 ControlData * main_control_data;
988 SubpanelData * subpanel_data;
993 /* Loop through the main controls to find the subpanel whose */
994 /* window matches the parameter shell window and then add the */
995 /* event handler for tear off behavoir. */
997 for (i = 0; i < panel.box_data_count; i++)
999 box_data = panel.box_data[i];
1001 for (j = 0; j < box_data->control_data_count; j++)
1003 main_control_data = box_data->control_data[j];
1005 if (main_control_data->subpanel_data != NULL &&
1006 XtWindow (main_control_data->subpanel_data->shell) == shell_window)
1008 subpanel_data = main_control_data->subpanel_data;
1010 subpanel_data->posted_x = XtX (subpanel_data->shell);
1012 XtAddEventHandler (subpanel_data->shell, StructureNotifyMask, False,
1013 (XtEventHandler) SubpanelTornEventHandler,
1014 (XtPointer) main_control_data);