1 /* editmenu.c - editable menus
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 2000 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
32 typedef struct W_EditMenuItem
{
36 struct W_EditMenu
*parent
;
41 WMCallback
*destroyData
;
43 struct W_EditMenu
*submenu
; /* if it's a cascade, NULL otherwise */
47 unsigned isHighlighted
:1;
52 typedef struct W_EditMenu
{
56 struct W_EditMenu
*parent
;
58 WMBag
*items
; /* EditMenuItem */
60 EditMenuItem
*selectedItem
;
69 WEditMenuDelegate
*delegate
;
75 /* only for non-standalone menu */
80 unsigned standalone
:1;
83 unsigned acceptsDrop
:1;
85 unsigned isSelectable
:1;
86 unsigned isEditable
:1;
90 unsigned isDragging
:1;
97 /******************** WEditMenuItem ********************/
99 static void destroyEditMenuItem(WEditMenuItem
*iPtr
);
100 static void paintEditMenuItem(WEditMenuItem
*iPtr
);
101 static void handleItemEvents(XEvent
*event
, void *data
);
103 static void handleItemClick(XEvent
*event
, void *data
);
106 static W_Class EditMenuItemClass
= 0;
110 InitEditMenuItem(WMScreen
*scr
)
112 /* register our widget with WINGs and get our widget class ID */
113 if (!EditMenuItemClass
) {
114 EditMenuItemClass
= W_RegisterUserWidget();
117 return EditMenuItemClass
;
122 WCreateEditMenuItem(WMWidget
*parent
, char *title
, Bool isTitle
)
125 WMScreen
*scr
= WMWidgetScreen(parent
);
127 if (!EditMenuItemClass
)
128 InitEditMenuItem(scr
);
131 iPtr
= wmalloc(sizeof(WEditMenuItem
));
133 memset(iPtr
, 0, sizeof(WEditMenuItem
));
135 iPtr
->widgetClass
= EditMenuItemClass
;
137 iPtr
->view
= W_CreateView(W_VIEW(parent
));
142 iPtr
->view
->self
= iPtr
;
144 iPtr
->parent
= parent
;
146 iPtr
->label
= wstrdup(title
);
148 iPtr
->flags
.isTitle
= isTitle
;
151 WMSetWidgetBackgroundColor(iPtr
, WMBlackColor(scr
));
154 WMCreateEventHandler(iPtr
->view
, ExposureMask
|StructureNotifyMask
,
155 handleItemEvents
, iPtr
);
157 WMCreateEventHandler(iPtr
->view
, ButtonPressMask
|ButtonReleaseMask
158 |ButtonMotionMask
, handleItemClick
, iPtr
);
165 char *WGetEditMenuItemTitle(WEditMenuItem
*item
)
171 void *WGetEditMenuItemData(WEditMenuItem
*item
)
177 void WSetEditMenuItemData(WEditMenuItem
*item
, void *data
,
178 WMCallback
*destroyer
)
181 item
->destroyData
= destroyer
;
188 paintEditMenuItem(WEditMenuItem
*iPtr
)
190 WMScreen
*scr
= WMWidgetScreen(iPtr
);
192 Window win
= W_VIEW(iPtr
)->window
;
193 int w
= W_VIEW(iPtr
)->size
.width
;
194 int h
= W_VIEW(iPtr
)->size
.height
;
195 WMFont
*font
= (iPtr
->flags
.isTitle
? scr
->boldFont
: scr
->normalFont
);
197 if (!iPtr
->view
->flags
.realized
)
201 if (iPtr
->flags
.isTitle
&& !iPtr
->flags
.isHighlighted
) {
206 XClearWindow(scr
->display
, win
);
208 W_DrawRelief(scr
, win
, 0, 0, w
+1, h
, WRRaised
);
210 WMDrawString(scr
, win
, WMColorGC(color
), font
, 5, 3, iPtr
->label
,
211 strlen(iPtr
->label
));
214 /* draw the cascade indicator */
215 XDrawLine(scr
->display
,win
,WMColorGC(scr
->darkGray
),
216 w
-11, 6, w
-6, h
/2-1);
217 XDrawLine(scr
->display
,win
,WMColorGC(scr
->white
),
218 w
-11, h
-8, w
-6, h
/2-1);
219 XDrawLine(scr
->display
,win
,WMColorGC(scr
->black
),
226 highlightItem(WEditMenuItem
*iPtr
, Bool high
)
228 if (iPtr
->flags
.isTitle
)
231 iPtr
->flags
.isHighlighted
= high
;
234 WMSetWidgetBackgroundColor(iPtr
, WMWhiteColor(WMWidgetScreen(iPtr
)));
236 if (!iPtr
->flags
.isTitle
) {
237 WMSetWidgetBackgroundColor(iPtr
,
238 WMGrayColor(WMWidgetScreen(iPtr
)));
240 WMSetWidgetBackgroundColor(iPtr
,
241 WMBlackColor(WMWidgetScreen(iPtr
)));
248 getItemTextWidth(WEditMenuItem
*iPtr
)
250 WMScreen
*scr
= WMWidgetScreen(iPtr
);
252 if (iPtr
->flags
.isTitle
) {
253 return WMWidthOfString(scr
->boldFont
, iPtr
->label
,
254 strlen(iPtr
->label
));
256 return WMWidthOfString(scr
->normalFont
, iPtr
->label
,
257 strlen(iPtr
->label
));
264 handleItemEvents(XEvent
*event
, void *data
)
266 WEditMenuItem
*iPtr
= (WEditMenuItem
*)data
;
268 switch (event
->type
) {
270 if (event
->xexpose
.count
!=0)
272 paintEditMenuItem(iPtr
);
276 destroyEditMenuItem(iPtr
);
283 destroyEditMenuItem(WEditMenuItem
*iPtr
)
287 if (iPtr
->data
&& iPtr
->destroyData
)
288 (*iPtr
->destroyData
)(iPtr
->data
);
295 /******************** WEditMenu *******************/
297 static void destroyEditMenu(WEditMenu
*mPtr
);
299 static void updateMenuContents(WEditMenu
*mPtr
);
301 static void handleEvents(XEvent
*event
, void *data
);
303 static void editItemLabel(WEditMenuItem
*item
);
304 static void stopEditItem(WEditMenu
*menu
, Bool apply
);
307 static void deselectItem(WEditMenu
*menu
);
310 static W_Class EditMenuClass
= 0;
314 InitEditMenu(WMScreen
*scr
)
316 /* register our widget with WINGs and get our widget class ID */
317 if (!EditMenuClass
) {
319 EditMenuClass
= W_RegisterUserWidget();
322 return EditMenuClass
;
332 Pixmap miniaturize_pixmap
; /* pixmap for miniaturize button */
333 Pixmap close_pixmap
; /* pixmap for close button */
334 Pixmap miniaturize_mask
; /* miniaturize pixmap mask */
335 Pixmap close_mask
; /* close pixmap mask */
337 } GNUstepWMAttributes
;
340 #define GSWindowStyleAttr (1<<0)
341 #define GSWindowLevelAttr (1<<1)
345 writeGNUstepWMAttr(WMScreen
*scr
, Window window
, GNUstepWMAttributes
*attr
)
347 unsigned long data
[9];
349 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
350 data
[0] = attr
->flags
;
351 data
[1] = attr
->window_style
;
352 data
[2] = attr
->window_level
;
353 data
[3] = 0; /* reserved */
354 /* The X protocol says XIDs are 32bit */
355 data
[4] = attr
->miniaturize_pixmap
;
356 data
[5] = attr
->close_pixmap
;
357 data
[6] = attr
->miniaturize_mask
;
358 data
[7] = attr
->close_mask
;
359 data
[8] = attr
->extra_flags
;
360 XChangeProperty(scr
->display
, window
, scr
->attribsAtom
, scr
->attribsAtom
,
361 32, PropModeReplace
, (unsigned char *)data
, 9);
366 realizeObserver(void *self
, WMNotification
*not)
368 WEditMenu
*menu
= (WEditMenu
*)self
;
369 GNUstepWMAttributes attribs
;
371 memset(&attribs
, 0, sizeof(GNUstepWMAttributes
));
372 attribs
.flags
= GSWindowStyleAttr
|GSWindowLevelAttr
;
373 attribs
.window_style
= WMBorderlessWindowMask
;
374 attribs
.window_level
= WMSubmenuWindowLevel
;
376 writeGNUstepWMAttr(WMWidgetScreen(menu
), menu
->view
->window
, &attribs
);
381 itemSelectObserver(void *self
, WMNotification
*notif
)
383 WEditMenu
*menu
= (WEditMenu
*)self
;
386 rmenu
= (WEditMenu
*)WMGetNotificationObject(notif
);
387 /* check whether rmenu is from the same hierarchy of menu? */
393 if (menu
->selectedItem
&& !menu
->selectedItem
->submenu
) {
400 makeEditMenu(WMScreen
*scr
, WMWidget
*parent
, char *title
)
409 mPtr
= wmalloc(sizeof(WEditMenu
));
410 memset(mPtr
, 0, sizeof(WEditMenu
));
412 mPtr
->widgetClass
= EditMenuClass
;
415 mPtr
->view
= W_CreateView(W_VIEW(parent
));
416 mPtr
->flags
.standalone
= 0;
418 mPtr
->view
= W_CreateTopView(scr
);
419 mPtr
->flags
.standalone
= 1;
425 mPtr
->view
->self
= mPtr
;
427 mPtr
->flags
.isSelectable
= 1;
428 mPtr
->flags
.isEditable
= 1;
430 W_SetViewBackgroundColor(mPtr
->view
, scr
->darkGray
);
432 WMAddNotificationObserver(realizeObserver
, mPtr
,
433 WMViewRealizedNotification
, mPtr
->view
);
435 WMAddNotificationObserver(itemSelectObserver
, mPtr
,
436 "EditMenuItemSelected", NULL
);
438 mPtr
->items
= WMCreateBag(4);
440 WMCreateEventHandler(mPtr
->view
, ExposureMask
|StructureNotifyMask
,
445 item
= WCreateEditMenuItem(mPtr
, title
, True
);
448 WMPutInBag(mPtr
->items
, item
);
450 mPtr
->flags
.isTitled
= 1;
453 mPtr
->itemHeight
= WMFontHeight(scr
->normalFont
) + 6;
454 mPtr
->titleHeight
= WMFontHeight(scr
->boldFont
) + 8;
456 updateMenuContents(mPtr
);
463 WCreateEditMenu(WMScreen
*scr
, char *title
)
465 return makeEditMenu(scr
, NULL
, title
);
470 WCreateEditMenuPad(WMWidget
*parent
)
472 return makeEditMenu(WMWidgetScreen(parent
), parent
, NULL
);
477 WSetEditMenuDelegate(WEditMenu
*mPtr
, WEditMenuDelegate
*delegate
)
479 mPtr
->delegate
= delegate
;
484 WInsertMenuItemWithTitle(WEditMenu
*mPtr
, int index
, char *title
)
488 item
= WCreateEditMenuItem(mPtr
, title
, False
);
492 if (index
>= WMGetBagItemCount(mPtr
->items
)) {
493 WMPutInBag(mPtr
->items
, item
);
497 if (mPtr
->flags
.isTitled
)
499 WMInsertInBag(mPtr
->items
, index
, item
);
502 updateMenuContents(mPtr
);
510 WAddMenuItemWithTitle(WEditMenu
*mPtr
, char *title
)
512 return WInsertMenuItemWithTitle(mPtr
, WMGetBagItemCount(mPtr
->items
),
519 WSetEditMenuTitle(WEditMenu
*mPtr
, char *title
)
523 item
= WMGetFromBag(mPtr
->items
, 0);
526 item
->label
= wstrdup(title
);
527 updateMenuContents(mPtr
);
532 WSetEditMenuAcceptsDrop(WEditMenu
*mPtr
, Bool flag
)
534 mPtr
->flags
.acceptsDrop
= flag
;
539 WSetEditMenuSubmenu(WEditMenu
*mPtr
, WEditMenuItem
*item
, WEditMenu
*submenu
)
541 item
->submenu
= submenu
;
542 submenu
->parent
= mPtr
;
544 paintEditMenuItem(item
);
549 WGetEditMenuSubmenu(WEditMenu
*mPtr
, WEditMenuItem
*item
)
551 return item
->submenu
;
555 static int simpleMatch(void *a
, void *b
)
565 WRemoveEditMenuItem(WEditMenu
*mPtr
, WEditMenuItem
*item
)
569 index
= WMFindInBag(mPtr
->items
, simpleMatch
, item
);
571 if (index
== WBNotFound
) {
575 WMDeleteFromBag(mPtr
->items
, index
);
577 updateMenuContents(mPtr
);
582 WSetEditMenuSelectable(WEditMenu
*mPtr
, Bool flag
)
584 mPtr
->flags
.isSelectable
= flag
;
589 WSetEditMenuEditable(WEditMenu
*mPtr
, Bool flag
)
591 mPtr
->flags
.isEditable
= flag
;
596 WSetEditMenuIsFactory(WEditMenu
*mPtr
, Bool flag
)
598 mPtr
->flags
.isFactory
= flag
;
603 WSetEditMenuMinSize(WEditMenu
*mPtr
, WMSize size
)
605 mPtr
->minSize
.width
= size
.width
;
606 mPtr
->minSize
.height
= size
.height
;
611 WSetEditMenuMaxSize(WEditMenu
*mPtr
, WMSize size
)
613 mPtr
->maxSize
.width
= size
.width
;
614 mPtr
->maxSize
.height
= size
.height
;
619 WGetEditMenuLocationForSubmenu(WEditMenu
*mPtr
, WEditMenu
*submenu
)
625 if (mPtr
->flags
.isTitled
)
626 y
= -mPtr
->titleHeight
;
629 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
630 if (item
->submenu
== submenu
) {
631 WMPoint pt
= WMGetViewScreenPosition(mPtr
->view
);
633 return wmkpoint(pt
.x
+ mPtr
->view
->size
.width
, pt
.y
+ y
);
635 y
+= W_VIEW_HEIGHT(item
->view
);
638 puts("invalid submenu passed to WGetEditMenuLocationForSubmenu()");
640 return wmkpoint(0,0);
646 closeMenuAction(WMWidget
*w
, void *data
)
648 WEditMenu
*menu
= (WEditMenu
*)data
;
650 WMAddIdleHandler(WMDestroyWidget
, menu
->closeB
);
658 WTearOffEditMenu(WEditMenu
*menu
, WEditMenu
*submenu
)
662 submenu
->flags
.isTornOff
= 1;
664 item
= (WEditMenuItem
*)WMGetFromBag(submenu
->items
, 0);
666 submenu
->closeB
= WMCreateCommandButton(item
);
667 WMResizeWidget(submenu
->closeB
, 15, 15);
668 WMMoveWidget(submenu
->closeB
, W_VIEW(submenu
)->size
.width
- 20, 3);
669 WMRealizeWidget(submenu
->closeB
);
670 WMSetButtonText(submenu
->closeB
, "X");
671 WMSetButtonAction(submenu
->closeB
, closeMenuAction
, submenu
);
672 WMMapWidget(submenu
->closeB
);
674 if (menu
->selectedItem
&& menu
->selectedItem
->submenu
== submenu
)
681 WEditMenuIsTornOff(WEditMenu
*mPtr
)
683 return mPtr
->flags
.isTornOff
;
688 updateMenuContents(WEditMenu
*mPtr
)
693 int iheight
= mPtr
->itemHeight
;
702 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
703 w
= getItemTextWidth(item
);
705 newW
= WMAX(w
, newW
);
707 WMMoveWidget(item
, offs
, newH
);
708 if (i
== 0 && mPtr
->flags
.isTitled
) {
709 newH
+= mPtr
->titleHeight
;
716 newW
+= iheight
+ 10;
719 if (mPtr
->minSize
.width
)
720 newW
= WMAX(newW
, mPtr
->minSize
.width
);
721 if (mPtr
->maxSize
.width
)
722 newW
= WMIN(newW
, mPtr
->maxSize
.width
);
724 if (mPtr
->minSize
.height
)
725 newH
= WMAX(newH
, mPtr
->minSize
.height
);
726 if (mPtr
->maxSize
.height
)
727 newH
= WMIN(newH
, mPtr
->maxSize
.height
);
729 W_ResizeView(mPtr
->view
, newW
, newH
+1);
734 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
735 if (i
== 0 && mPtr
->flags
.isTitled
) {
736 WMResizeWidget(item
, newW
, mPtr
->titleHeight
);
738 WMResizeWidget(item
, newW
, iheight
);
746 unmapMenu(WEditMenu
*menu
)
750 if (menu
->selectedItem
) {
757 deselectItem(WEditMenu
*menu
)
760 WEditMenuItem
*item
= menu
->selectedItem
;
762 highlightItem(item
, False
);
764 if (menu
->delegate
&& menu
->delegate
->itemDeselected
) {
765 (*menu
->delegate
->itemDeselected
)(menu
->delegate
, menu
, item
);
767 submenu
= item
->submenu
;
769 if (submenu
&& !WEditMenuIsTornOff(submenu
)) {
773 menu
->selectedItem
= NULL
;
778 selectItem(WEditMenu
*menu
, WEditMenuItem
*item
)
780 if (!menu
->flags
.isSelectable
|| menu
->selectedItem
== item
) {
783 if (menu
->selectedItem
) {
787 if (menu
->flags
.isEditing
) {
788 stopEditItem(menu
, False
);
791 if (item
&& !item
->flags
.isTitle
) {
792 highlightItem(item
, True
);
798 hints
= XAllocSizeHints();
800 pt
= WGetEditMenuLocationForSubmenu(menu
, item
->submenu
);
802 hints
->flags
= USPosition
;
806 WMMoveWidget(item
->submenu
, pt
.x
, pt
.y
);
807 XSetWMNormalHints(W_VIEW_DISPLAY(item
->submenu
->view
),
808 W_VIEW_DRAWABLE(item
->submenu
->view
),
811 WMMapWidget(item
->submenu
);
813 item
->submenu
->flags
.isTornOff
= 0;
816 WMPostNotificationName("EditMenuItemSelected", menu
, NULL
);
818 if (menu
->delegate
&& menu
->delegate
->itemSelected
) {
819 (*menu
->delegate
->itemSelected
)(menu
->delegate
, menu
, item
);
823 menu
->selectedItem
= item
;
828 paintMenu(WEditMenu
*mPtr
)
830 W_View
*view
= mPtr
->view
;
832 W_DrawRelief(W_VIEW_SCREEN(view
), W_VIEW_DRAWABLE(view
), 0, 0,
833 W_VIEW_WIDTH(view
), W_VIEW_HEIGHT(view
), WRSimple
);
838 handleEvents(XEvent
*event
, void *data
)
840 WEditMenu
*mPtr
= (WEditMenu
*)data
;
842 switch (event
->type
) {
844 destroyEditMenu(mPtr
);
848 if (event
->xexpose
.count
== 0)
857 /* -------------------------- Menu Label Editing ------------------------ */
861 stopEditItem(WEditMenu
*menu
, Bool apply
)
866 text
= WMGetTextFieldText(menu
->tfield
);
868 free(menu
->selectedItem
->label
);
869 menu
->selectedItem
->label
= wstrdup(text
);
871 updateMenuContents(menu
);
873 WMUnmapWidget(menu
->tfield
);
874 menu
->flags
.isEditing
= 0;
879 textEndedEditing(struct WMTextFieldDelegate
*self
, WMNotification
*notif
)
881 WEditMenu
*menu
= (WEditMenu
*)self
->data
;
886 if (!menu
->flags
.isEditing
)
889 reason
= (int)WMGetNotificationClientData(notif
);
892 case WMEscapeTextMovement
:
893 stopEditItem(menu
, False
);
896 case WMReturnTextMovement
:
897 stopEditItem(menu
, True
);
900 case WMTabTextMovement
:
901 stopEditItem(menu
, True
);
903 i
= WMFindInBag(menu
->items
, simpleMatch
, menu
->selectedItem
);
904 item
= WMGetFromBag(menu
->items
, i
+1);
906 selectItem(menu
, item
);
911 case WMBacktabTextMovement
:
912 stopEditItem(menu
, True
);
914 i
= WMFindInBag(menu
->items
, simpleMatch
, menu
->selectedItem
);
915 item
= WMGetFromBag(menu
->items
, i
-1);
917 selectItem(menu
, item
);
926 static WMTextFieldDelegate textFieldDelegate
= {
937 editItemLabel(WEditMenuItem
*item
)
939 WEditMenu
*mPtr
= item
->parent
;
943 if (!mPtr
->flags
.isEditable
) {
948 mPtr
->tfield
= WMCreateTextField(mPtr
);
949 WMSetTextFieldBeveled(mPtr
->tfield
, False
);
950 WMRealizeWidget(mPtr
->tfield
);
952 textFieldDelegate
.data
= mPtr
;
954 WMSetTextFieldDelegate(mPtr
->tfield
, &textFieldDelegate
);
958 i
= WMFindInBag(mPtr
->items
, simpleMatch
, item
);
960 WMSetTextFieldText(tf
, item
->label
);
961 WMSelectTextFieldRange(tf
, wmkrange(0, strlen(item
->label
)));
962 WMResizeWidget(tf
, mPtr
->view
->size
.width
, mPtr
->itemHeight
);
963 WMMoveWidget(tf
, 0, item
->view
->pos
.y
);
965 WMSetFocusToWidget(tf
);
967 mPtr
->flags
.isEditing
= 1;
972 /* -------------------------------------------------- */
976 slideWindow(Display
*dpy
, Window win
, int srcX
, int srcY
, int dstX
, int dstY
)
982 iterations
= WMIN(25, WMAX(abs(dstX
-srcX
), abs(dstY
-srcY
)));
987 dx
= (double)(dstX
-srcX
)/iterations
;
988 dy
= (double)(dstY
-srcY
)/iterations
;
990 for (i
= 0; i
<= iterations
; i
++) {
991 XMoveWindow(dpy
, win
, x
, y
);
1002 static int errorHandler(Display
*d
, XErrorEvent
*ev
)
1010 findMenuInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
1018 int (*oldHandler
)(Display
*, XErrorEvent
*);
1020 view
= W_GetViewForXWindow(dpy
, toplevel
);
1021 if (view
&& view
->self
&& WMWidgetClass(view
->self
) == EditMenuClass
) {
1022 menu
= (WEditMenu
*)view
->self
;
1023 if (menu
->flags
.acceptsDrop
) {
1028 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
1029 &children
, &nchildren
) || children
== NULL
) {
1033 oldHandler
= XSetErrorHandler(errorHandler
);
1035 /* first window that contains the point is the one */
1036 for (i
= nchildren
-1; i
>= 0; i
--) {
1037 XWindowAttributes attr
;
1039 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
1040 && attr
.map_state
== IsViewable
1041 && x
>= attr
.x
&& y
>= attr
.y
1042 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
1047 menu
= findMenuInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
1055 XSetErrorHandler(oldHandler
);
1063 handleDragOver(WEditMenu
*menu
, WMView
*view
, WEditMenuItem
*item
,
1066 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1071 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1072 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
1074 offs
= menu
->flags
.standalone
? 0 : 1;
1076 W_MoveView(view
, mx
+ offs
, y
);
1077 if (view
->size
.width
!= menu
->view
->size
.width
) {
1078 W_ResizeView(view
, menu
->view
->size
.width
- 2*offs
,
1080 W_ResizeView(item
->view
, menu
->view
->size
.width
- 2*offs
,
1087 handleItemDrop(WEditMenu
*menu
, WEditMenuItem
*item
, int x
, int y
)
1089 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1094 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1095 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
1098 if (menu
->flags
.isTitled
) {
1099 index
-= menu
->titleHeight
;
1101 index
= (index
+ menu
->itemHeight
/2) / menu
->itemHeight
;
1105 if (menu
->flags
.isTitled
) {
1109 if (index
> WMGetBagItemCount(menu
->items
)) {
1110 WMPutInBag(menu
->items
, item
);
1112 WMInsertInBag(menu
->items
, index
, item
);
1115 W_ReparentView(item
->view
, menu
->view
, 0, index
*menu
->itemHeight
);
1117 item
->parent
= menu
;
1118 if (item
->submenu
) {
1119 item
->submenu
->parent
= menu
;
1122 updateMenuContents(menu
);
1127 dragMenu(WEditMenu
*menu
)
1129 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1136 XGetGeometry(scr
->display
, W_VIEW_DRAWABLE(menu
->view
), &blaw
, &dx
, &dy
,
1137 &blau
, &blau
, &blau
, &blau
);
1139 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1140 scr
->rootWin
, dx
, dy
, &dx
, &dy
, &blaw
);
1142 dx
= menu
->dragX
- dx
;
1143 dy
= menu
->dragY
- dy
;
1145 XGrabPointer(scr
->display
, scr
->rootWin
, False
,
1146 ButtonReleaseMask
|ButtonMotionMask
,
1147 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1151 WTearOffEditMenu(menu
->parent
, menu
);
1154 WMNextEvent(scr
->display
, &ev
);
1162 WMMoveWidget(menu
, ev
.xmotion
.x_root
- dx
,
1163 ev
.xmotion
.y_root
- dy
);
1172 XUngrabPointer(scr
->display
, CurrentTime
);
1177 duplicateMenu(WEditMenu
*menu
)
1180 WEditMenuItem
*title
;
1182 if (menu
->flags
.isTitled
) {
1183 title
= WMGetFromBag(menu
->items
, 0);
1186 nmenu
= WCreateEditMenu(WMWidgetScreen(menu
), title
->label
);
1188 memcpy(&nmenu
->flags
, &menu
->flags
, sizeof(menu
->flags
));
1189 nmenu
->delegate
= menu
->delegate
;
1191 WMRealizeWidget(nmenu
);
1198 dragItem(WEditMenu
*menu
, WEditMenuItem
*item
)
1200 Display
*dpy
= W_VIEW_DISPLAY(menu
->view
);
1201 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1211 Bool enteredMenu
= False
;
1212 WMSize oldSize
= item
->view
->size
;
1213 WEditMenuItem
*dritem
= item
;
1214 WEditMenu
*dmenu
= NULL
;
1217 if (item
->flags
.isTitle
) {
1218 WMRaiseWidget(menu
);
1226 selectItem(menu
, NULL
);
1230 XTranslateCoordinates(dpy
, W_VIEW_DRAWABLE(item
->view
), win
,
1231 0, 0, &orix
, &oriy
, &blaw
);
1233 dview
= W_CreateUnmanagedTopView(scr
);
1234 W_SetViewBackgroundColor(dview
, scr
->black
);
1235 W_ResizeView(dview
, W_VIEW_WIDTH(item
->view
), W_VIEW_HEIGHT(item
->view
));
1236 W_MoveView(dview
, orix
, oriy
);
1237 W_RealizeView(dview
);
1239 if (menu
->flags
.isFactory
) {
1240 dritem
= WCreateEditMenuItem(menu
, item
->label
, False
);
1242 W_ReparentView(dritem
->view
, dview
, 0, 0);
1243 WMResizeWidget(dritem
, oldSize
.width
, oldSize
.height
);
1244 WMRealizeWidget(dritem
);
1245 WMMapWidget(dritem
);
1247 W_ReparentView(item
->view
, dview
, 0, 0);
1252 dx
= menu
->dragX
- orix
;
1253 dy
= menu
->dragY
- oriy
;
1255 XGrabPointer(dpy
, scr
->rootWin
, False
,
1256 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
1257 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1263 WMNextEvent(dpy
, &ev
);
1267 XQueryPointer(dpy
, win
, &blaw
, &blaw
, &blai
, &blai
, &x
, &y
, &blau
);
1269 dmenu
= findMenuInWindow(dpy
, win
, x
, y
);
1272 handleDragOver(dmenu
, dview
, dritem
, x
- dx
, y
- dy
);
1276 W_ResizeView(dview
, oldSize
.width
, oldSize
.height
);
1277 W_ResizeView(dritem
->view
, oldSize
.width
, oldSize
.height
);
1278 enteredMenu
= False
;
1280 W_MoveView(dview
, x
- dx
, y
- dy
);
1294 XUngrabPointer(dpy
, CurrentTime
);
1300 if (!menu
->flags
.isFactory
) {
1301 WMUnmapWidget(dritem
);
1302 if (menu
->delegate
&& menu
->delegate
->shouldRemoveItem
) {
1303 rem
= (*menu
->delegate
->shouldRemoveItem
)(menu
->delegate
,
1306 WMMapWidget(dritem
);
1309 if (!rem
|| menu
->flags
.isFactory
) {
1310 slideWindow(dpy
, W_VIEW_DRAWABLE(dview
), x
-dx
, y
-dy
, orix
, oriy
);
1312 if (!menu
->flags
.isFactory
) {
1313 WRemoveEditMenuItem(menu
, dritem
);
1314 handleItemDrop(dmenu
? dmenu
: menu
, dritem
, orix
, oriy
);
1317 WRemoveEditMenuItem(menu
, dritem
);
1320 WRemoveEditMenuItem(menu
, dritem
);
1322 if (menu
->delegate
&& menu
->delegate
->itemCloned
) {
1323 (*menu
->delegate
->itemCloned
)(menu
->delegate
, menu
,
1327 handleItemDrop(dmenu
, dritem
, x
-dy
, y
-dy
);
1329 if (item
->submenu
&& menu
->flags
.isFactory
) {
1332 submenu
= duplicateMenu(item
->submenu
);
1333 WSetEditMenuSubmenu(dmenu
, dritem
, submenu
);
1337 /* can't destroy now because we're being called from
1338 * the event handler of the item. and destroying now,
1339 * would mean destroying the item too in some cases.
1341 WMAddIdleHandler((WMCallback
*)W_DestroyView
, dview
);
1347 handleItemClick(XEvent
*event
, void *data
)
1349 WEditMenuItem
*item
= (WEditMenuItem
*)data
;
1350 WEditMenu
*menu
= item
->parent
;
1352 switch (event
->type
) {
1354 selectItem(menu
, item
);
1356 if (WMIsDoubleClick(event
)) {
1357 editItemLabel(item
);
1360 menu
->flags
.isDragging
= 1;
1361 menu
->dragX
= event
->xbutton
.x_root
;
1362 menu
->dragY
= event
->xbutton
.y_root
;
1366 menu
->flags
.isDragging
= 0;
1370 if (menu
->flags
.isDragging
) {
1371 if (abs(event
->xbutton
.x_root
- menu
->dragX
) > 5
1372 || abs(event
->xbutton
.y_root
- menu
->dragY
) > 5) {
1373 menu
->flags
.isDragging
= 0;
1374 dragItem(menu
, item
);
1383 destroyEditMenu(WEditMenu
*mPtr
)
1385 WEditMenuItem
*item
;
1388 WMRemoveNotificationObserver(mPtr
);
1390 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
1391 if (item
->submenu
) {
1392 WMDestroyWidget(item
->submenu
);
1396 WMFreeBag(mPtr
->items
);