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
;
67 WEditMenuDelegate
*delegate
;
73 struct W_EditMenu
**dropTargets
;
75 /* only for non-standalone menu */
80 unsigned standalone
:1;
84 unsigned isSelectable
:1;
85 unsigned isEditable
:1;
89 unsigned isDragging
:1;
96 /******************** WEditMenuItem ********************/
98 static void destroyEditMenuItem(WEditMenuItem
*iPtr
);
99 static void paintEditMenuItem(WEditMenuItem
*iPtr
);
100 static void handleItemEvents(XEvent
*event
, void *data
);
102 static void handleItemClick(XEvent
*event
, void *data
);
105 static W_Class EditMenuItemClass
= 0;
109 InitEditMenuItem(WMScreen
*scr
)
111 /* register our widget with WINGs and get our widget class ID */
112 if (!EditMenuItemClass
) {
113 EditMenuItemClass
= W_RegisterUserWidget();
116 return EditMenuItemClass
;
121 WCreateEditMenuItem(WMWidget
*parent
, char *title
, Bool isTitle
)
124 WMScreen
*scr
= WMWidgetScreen(parent
);
126 if (!EditMenuItemClass
)
127 InitEditMenuItem(scr
);
130 iPtr
= wmalloc(sizeof(WEditMenuItem
));
132 memset(iPtr
, 0, sizeof(WEditMenuItem
));
134 iPtr
->widgetClass
= EditMenuItemClass
;
136 iPtr
->view
= W_CreateView(W_VIEW(parent
));
141 iPtr
->view
->self
= iPtr
;
143 iPtr
->parent
= parent
;
145 iPtr
->label
= wstrdup(title
);
147 iPtr
->flags
.isTitle
= isTitle
;
150 WMSetWidgetBackgroundColor(iPtr
, WMBlackColor(scr
));
153 WMCreateEventHandler(iPtr
->view
, ExposureMask
|StructureNotifyMask
,
154 handleItemEvents
, iPtr
);
156 WMCreateEventHandler(iPtr
->view
, ButtonPressMask
|ButtonReleaseMask
157 |ButtonMotionMask
, handleItemClick
, iPtr
);
164 void *WGetEditMenuItemData(WEditMenuItem
*item
)
170 void WSetEditMenuItemData(WEditMenuItem
*item
, void *data
,
171 WMCallback
*destroyer
)
174 item
->destroyData
= destroyer
;
181 paintEditMenuItem(WEditMenuItem
*iPtr
)
183 WMScreen
*scr
= WMWidgetScreen(iPtr
);
185 Window win
= W_VIEW(iPtr
)->window
;
186 int w
= W_VIEW(iPtr
)->size
.width
;
187 int h
= W_VIEW(iPtr
)->size
.height
;
188 WMFont
*font
= (iPtr
->flags
.isTitle
? scr
->boldFont
: scr
->normalFont
);
190 if (!iPtr
->view
->flags
.realized
)
194 if (iPtr
->flags
.isTitle
&& !iPtr
->flags
.isHighlighted
) {
199 XClearWindow(scr
->display
, win
);
201 W_DrawRelief(scr
, win
, 0, 0, w
+1, h
, WRRaised
);
203 WMDrawString(scr
, win
, WMColorGC(color
), font
, 5, 3, iPtr
->label
,
204 strlen(iPtr
->label
));
207 /* draw the cascade indicator */
208 XDrawLine(scr
->display
,win
,WMColorGC(scr
->darkGray
),
209 w
-11, 6, w
-6, h
/2-1);
210 XDrawLine(scr
->display
,win
,WMColorGC(scr
->white
),
211 w
-11, h
-8, w
-6, h
/2-1);
212 XDrawLine(scr
->display
,win
,WMColorGC(scr
->black
),
219 highlightItem(WEditMenuItem
*iPtr
, Bool high
)
221 if (iPtr
->flags
.isTitle
)
224 iPtr
->flags
.isHighlighted
= high
;
227 WMSetWidgetBackgroundColor(iPtr
, WMWhiteColor(WMWidgetScreen(iPtr
)));
229 if (!iPtr
->flags
.isTitle
) {
230 WMSetWidgetBackgroundColor(iPtr
,
231 WMGrayColor(WMWidgetScreen(iPtr
)));
233 WMSetWidgetBackgroundColor(iPtr
,
234 WMBlackColor(WMWidgetScreen(iPtr
)));
241 getItemTextWidth(WEditMenuItem
*iPtr
)
243 WMScreen
*scr
= WMWidgetScreen(iPtr
);
245 if (iPtr
->flags
.isTitle
) {
246 return WMWidthOfString(scr
->boldFont
, iPtr
->label
,
247 strlen(iPtr
->label
));
249 return WMWidthOfString(scr
->normalFont
, iPtr
->label
,
250 strlen(iPtr
->label
));
257 handleItemEvents(XEvent
*event
, void *data
)
259 WEditMenuItem
*iPtr
= (WEditMenuItem
*)data
;
261 switch (event
->type
) {
263 if (event
->xexpose
.count
!=0)
265 paintEditMenuItem(iPtr
);
269 destroyEditMenuItem(iPtr
);
276 destroyEditMenuItem(WEditMenuItem
*iPtr
)
280 if (iPtr
->data
&& iPtr
->destroyData
)
281 (*iPtr
->destroyData
)(iPtr
->data
);
288 /******************** WEditMenu *******************/
290 static void destroyEditMenu(WEditMenu
*mPtr
);
292 static void updateMenuContents(WEditMenu
*mPtr
);
294 static void handleEvents(XEvent
*event
, void *data
);
295 static void handleActionEvents(XEvent
*event
, void *data
);
297 static void editItemLabel(WEditMenuItem
*item
);
298 static void stopEditItem(WEditMenu
*menu
, Bool apply
);
301 static W_Class EditMenuClass
= 0;
305 InitEditMenu(WMScreen
*scr
)
307 /* register our widget with WINGs and get our widget class ID */
308 if (!EditMenuClass
) {
310 EditMenuClass
= W_RegisterUserWidget();
313 return EditMenuClass
;
323 Pixmap miniaturize_pixmap
; /* pixmap for miniaturize button */
324 Pixmap close_pixmap
; /* pixmap for close button */
325 Pixmap miniaturize_mask
; /* miniaturize pixmap mask */
326 Pixmap close_mask
; /* close pixmap mask */
328 } GNUstepWMAttributes
;
331 #define GSWindowStyleAttr (1<<0)
332 #define GSWindowLevelAttr (1<<1)
336 writeGNUstepWMAttr(WMScreen
*scr
, Window window
, GNUstepWMAttributes
*attr
)
338 unsigned long data
[9];
340 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
341 data
[0] = attr
->flags
;
342 data
[1] = attr
->window_style
;
343 data
[2] = attr
->window_level
;
344 data
[3] = 0; /* reserved */
345 /* The X protocol says XIDs are 32bit */
346 data
[4] = attr
->miniaturize_pixmap
;
347 data
[5] = attr
->close_pixmap
;
348 data
[6] = attr
->miniaturize_mask
;
349 data
[7] = attr
->close_mask
;
350 data
[8] = attr
->extra_flags
;
351 XChangeProperty(scr
->display
, window
, scr
->attribsAtom
, scr
->attribsAtom
,
352 32, PropModeReplace
, (unsigned char *)data
, 9);
357 realizeObserver(void *self
, WMNotification
*not)
359 WEditMenu
*menu
= (WEditMenu
*)self
;
360 GNUstepWMAttributes attribs
;
362 memset(&attribs
, 0, sizeof(GNUstepWMAttributes
));
363 attribs
.flags
= GSWindowStyleAttr
|GSWindowLevelAttr
;
364 attribs
.window_style
= WMBorderlessWindowMask
;
365 attribs
.window_level
= WMSubmenuWindowLevel
;
367 writeGNUstepWMAttr(WMWidgetScreen(menu
), menu
->view
->window
, &attribs
);
372 makeEditMenu(WMScreen
*scr
, WMWidget
*parent
, char *title
)
381 mPtr
= wmalloc(sizeof(WEditMenu
));
382 memset(mPtr
, 0, sizeof(WEditMenu
));
384 mPtr
->widgetClass
= EditMenuClass
;
387 mPtr
->view
= W_CreateView(W_VIEW(parent
));
388 mPtr
->flags
.standalone
= 0;
390 mPtr
->view
= W_CreateTopView(scr
);
391 mPtr
->flags
.standalone
= 1;
397 mPtr
->view
->self
= mPtr
;
399 mPtr
->flags
.isSelectable
= 1;
400 mPtr
->flags
.isEditable
= 1;
402 W_SetViewBackgroundColor(mPtr
->view
, scr
->darkGray
);
404 WMAddNotificationObserver(realizeObserver
, mPtr
,
405 WMViewRealizedNotification
, mPtr
->view
);
407 mPtr
->items
= WMCreateBag(4);
409 WMCreateEventHandler(mPtr
->view
, ExposureMask
|StructureNotifyMask
,
412 WMCreateEventHandler(mPtr
->view
, ButtonPressMask
,handleActionEvents
, mPtr
);
416 item
= WCreateEditMenuItem(mPtr
, title
, True
);
419 WMPutInBag(mPtr
->items
, item
);
421 mPtr
->flags
.isTitled
= 1;
424 mPtr
->itemHeight
= WMFontHeight(scr
->normalFont
) + 6;
425 mPtr
->titleHeight
= WMFontHeight(scr
->boldFont
) + 8;
427 updateMenuContents(mPtr
);
434 WCreateEditMenu(WMScreen
*scr
, char *title
)
436 return makeEditMenu(scr
, NULL
, title
);
441 WCreateEditMenuPad(WMWidget
*parent
)
443 return makeEditMenu(WMWidgetScreen(parent
), parent
, NULL
);
448 WSetEditMenuDelegate(WEditMenu
*mPtr
, WEditMenuDelegate
*delegate
)
450 mPtr
->delegate
= delegate
;
455 WInsertMenuItemWithTitle(WEditMenu
*mPtr
, int index
, char *title
)
459 item
= WCreateEditMenuItem(mPtr
, title
, False
);
463 if (index
>= WMGetBagItemCount(mPtr
->items
))
464 WMPutInBag(mPtr
->items
, item
);
468 if (mPtr
->flags
.isTitled
)
470 WMInsertInBag(mPtr
->items
, index
, item
);
473 updateMenuContents(mPtr
);
481 WAddMenuItemWithTitle(WEditMenu
*mPtr
, char *title
)
483 return WInsertMenuItemWithTitle(mPtr
, WMGetBagItemCount(mPtr
->items
),
489 WSetEditMenuItemDropTargets(WEditMenu
*mPtr
, WEditMenu
**dropTargets
,
492 if (mPtr
->dropTargets
)
493 free(mPtr
->dropTargets
);
495 mPtr
->dropTargets
= wmalloc(sizeof(WEditMenu
*)*(count
+1));
496 memcpy(mPtr
->dropTargets
, dropTargets
, sizeof(WEditMenu
*)*count
);
497 mPtr
->dropTargets
[count
] = NULL
;
502 WSetEditMenuSubmenu(WEditMenu
*mPtr
, WEditMenuItem
*item
, WEditMenu
*submenu
)
504 item
->submenu
= submenu
;
505 submenu
->parent
= mPtr
;
507 paintEditMenuItem(item
);
510 static int simpleMatch(void *a
, void *b
)
520 WRemoveEditMenuItem(WEditMenu
*mPtr
, WEditMenuItem
*item
)
524 index
= WMFindInBag(mPtr
->items
, simpleMatch
, item
);
526 if (index
== WBNotFound
) {
530 WMDeleteFromBag(mPtr
->items
, index
);
532 updateMenuContents(mPtr
);
537 WSetEditMenuSelectable(WEditMenu
*mPtr
, Bool flag
)
539 mPtr
->flags
.isSelectable
= flag
;
544 WSetEditMenuEditable(WEditMenu
*mPtr
, Bool flag
)
546 mPtr
->flags
.isEditable
= flag
;
551 WSetEditMenuIsFactory(WEditMenu
*mPtr
, Bool flag
)
553 mPtr
->flags
.isFactory
= flag
;
558 WSetEditMenuMinSize(WEditMenu
*mPtr
, WMSize size
)
560 mPtr
->minSize
.width
= size
.width
;
561 mPtr
->minSize
.height
= size
.height
;
566 WSetEditMenuMaxSize(WEditMenu
*mPtr
, WMSize size
)
568 mPtr
->maxSize
.width
= size
.width
;
569 mPtr
->maxSize
.height
= size
.height
;
574 WGetEditMenuLocationForSubmenu(WEditMenu
*mPtr
, WEditMenu
*submenu
)
580 if (mPtr
->flags
.isTitled
) {
581 y
= mPtr
->titleHeight
;
585 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
586 if (item
->submenu
== submenu
) {
587 return wmkpoint(mPtr
->view
->pos
.x
+ mPtr
->view
->size
.width
, y
);
589 y
+= mPtr
->itemHeight
;
592 puts("invalid submenu passed to WGetEditMenuLocationForSubmenu()");
594 return wmkpoint(0,0);
599 WEditMenuIsTornOff(WEditMenu
*mPtr
)
601 return !mPtr
->flags
.isTornOff
;
606 updateMenuContents(WEditMenu
*mPtr
)
611 int iheight
= mPtr
->itemHeight
;
620 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
621 w
= getItemTextWidth(item
);
623 newW
= WMAX(w
, newW
);
625 WMMoveWidget(item
, offs
, newH
);
626 if (i
== 0 && mPtr
->flags
.isTitled
) {
627 newH
+= mPtr
->titleHeight
;
637 if (mPtr
->minSize
.width
)
638 newW
= WMAX(newW
, mPtr
->minSize
.width
);
639 if (mPtr
->maxSize
.width
)
640 newW
= WMIN(newW
, mPtr
->maxSize
.width
);
642 if (mPtr
->minSize
.height
)
643 newH
= WMAX(newH
, mPtr
->minSize
.height
);
644 if (mPtr
->maxSize
.height
)
645 newH
= WMIN(newH
, mPtr
->maxSize
.height
);
647 W_ResizeView(mPtr
->view
, newW
, newH
+1);
652 WM_ITERATE_BAG(mPtr
->items
, item
, iter
) {
653 if (i
== 0 && mPtr
->flags
.isTitled
) {
654 WMResizeWidget(item
, newW
, mPtr
->titleHeight
);
656 WMResizeWidget(item
, newW
, iheight
);
664 selectItem(WEditMenu
*menu
, WEditMenuItem
*item
)
666 if (!menu
->flags
.isSelectable
) {
670 if (menu
->selectedItem
) {
671 highlightItem(menu
->selectedItem
, False
);
673 if (menu
->delegate
) {
674 (*menu
->delegate
->itemDeselected
)(menu
->delegate
, menu
,
679 if (menu
->flags
.isEditing
) {
680 stopEditItem(menu
, False
);
684 highlightItem(item
, True
);
689 pt
= WGetEditMenuLocationForSubmenu(menu
, item
->submenu
);
690 WMMoveWidget(item
->submenu
, pt
.x
, pt
.y
);
691 WMMapWidget(item
->submenu
);
694 if (menu
->delegate
) {
695 (*menu
->delegate
->itemSelected
)(menu
->delegate
, menu
, item
);
699 menu
->selectedItem
= item
;
704 paintMenu(WEditMenu
*mPtr
)
706 W_View
*view
= mPtr
->view
;
708 W_DrawRelief(W_VIEW_SCREEN(view
), W_VIEW_DRAWABLE(view
), 0, 0,
709 W_VIEW_WIDTH(view
), W_VIEW_HEIGHT(view
), WRSimple
);
714 handleEvents(XEvent
*event
, void *data
)
716 WEditMenu
*mPtr
= (WEditMenu
*)data
;
718 switch (event
->type
) {
720 destroyEditMenu(mPtr
);
724 if (event
->xexpose
.count
== 0)
734 handleActionEvents(XEvent
*event
, void *data
)
736 // WEditMenu *mPtr = (WEditMenu*)data;
738 switch (event
->type
) {
745 /* -------------------------- Menu Label Editing ------------------------ */
749 stopEditItem(WEditMenu
*menu
, Bool apply
)
754 text
= WMGetTextFieldText(menu
->tfield
);
756 free(menu
->selectedItem
->label
);
757 menu
->selectedItem
->label
= wstrdup(text
);
759 updateMenuContents(menu
);
761 WMUnmapWidget(menu
->tfield
);
762 menu
->flags
.isEditing
= 0;
767 textEndedEditing(struct WMTextFieldDelegate
*self
, WMNotification
*notif
)
769 WEditMenu
*menu
= (WEditMenu
*)self
->data
;
774 if (!menu
->flags
.isEditing
)
777 reason
= (int)WMGetNotificationClientData(notif
);
780 case WMEscapeTextMovement
:
781 stopEditItem(menu
, False
);
784 case WMReturnTextMovement
:
785 stopEditItem(menu
, True
);
788 case WMTabTextMovement
:
789 stopEditItem(menu
, True
);
791 i
= WMFindInBag(menu
->items
, simpleMatch
, menu
->selectedItem
);
792 item
= WMGetFromBag(menu
->items
, i
+1);
794 selectItem(menu
, item
);
799 case WMBacktabTextMovement
:
800 stopEditItem(menu
, True
);
802 i
= WMFindInBag(menu
->items
, simpleMatch
, menu
->selectedItem
);
803 item
= WMGetFromBag(menu
->items
, i
-1);
805 selectItem(menu
, item
);
814 static WMTextFieldDelegate textFieldDelegate
= {
825 editItemLabel(WEditMenuItem
*item
)
827 WEditMenu
*mPtr
= item
->parent
;
831 if (!mPtr
->flags
.isEditable
) {
836 mPtr
->tfield
= WMCreateTextField(mPtr
);
837 WMSetTextFieldBeveled(mPtr
->tfield
, False
);
838 WMRealizeWidget(mPtr
->tfield
);
840 textFieldDelegate
.data
= mPtr
;
842 WMSetTextFieldDelegate(mPtr
->tfield
, &textFieldDelegate
);
846 i
= WMFindInBag(mPtr
->items
, simpleMatch
, item
);
848 WMSetTextFieldText(tf
, item
->label
);
849 WMSelectTextFieldRange(tf
, wmkrange(0, strlen(item
->label
)));
850 WMResizeWidget(tf
, mPtr
->view
->size
.width
, mPtr
->itemHeight
);
851 WMMoveWidget(tf
, 0, item
->view
->pos
.y
);
853 WMSetFocusToWidget(tf
);
855 mPtr
->flags
.isEditing
= 1;
860 /* -------------------------------------------------- */
864 slideWindow(Display
*dpy
, Window win
, int srcX
, int srcY
, int dstX
, int dstY
)
870 iterations
= WMIN(25, WMAX(abs(dstX
-srcX
), abs(dstY
-srcY
)));
875 dx
= (double)(dstX
-srcX
)/iterations
;
876 dy
= (double)(dstY
-srcY
)/iterations
;
878 for (i
= 0; i
<= iterations
; i
++) {
879 XMoveWindow(dpy
, win
, x
, y
);
891 getEditMenuForWindow(WEditMenu
**menus
, Window window
)
894 if (W_VIEW_DRAWABLE((*menus
)->view
) == window
) {
905 findMenuInWindow(Display
*dpy
, Window toplevel
, int x
, int y
,
914 menu
= getEditMenuForWindow(menus
, toplevel
);
918 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
919 &children
, &nchildren
) || children
== NULL
) {
923 /* first window that contains the point is the one */
924 for (i
= nchildren
-1; i
>= 0; i
--) {
925 XWindowAttributes attr
;
927 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
928 && attr
.map_state
== IsViewable
929 && x
>= attr
.x
&& y
>= attr
.y
930 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
935 menu
= findMenuInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
, menus
);
949 handleDragOver(WEditMenu
*menu
, WMView
*view
, WEditMenuItem
*item
,
952 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
957 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
958 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
960 offs
= menu
->flags
.standalone
? 0 : 1;
962 W_MoveView(view
, mx
+ offs
, y
);
963 if (view
->size
.width
!= menu
->view
->size
.width
) {
964 W_ResizeView(view
, menu
->view
->size
.width
- 2*offs
,
966 W_ResizeView(item
->view
, menu
->view
->size
.width
- 2*offs
,
973 handleItemDrop(WEditMenu
*menu
, WEditMenuItem
*item
, int x
, int y
)
975 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
980 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
981 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
984 if (menu
->flags
.isTitled
) {
985 index
-= menu
->titleHeight
;
987 index
= (index
+ menu
->itemHeight
/2) / menu
->itemHeight
;
991 if (menu
->flags
.isTitled
) {
995 if (index
> WMGetBagItemCount(menu
->items
)) {
996 WMPutInBag(menu
->items
, item
);
998 WMInsertInBag(menu
->items
, index
, item
);
1001 W_ReparentView(item
->view
, menu
->view
, 0, index
*menu
->itemHeight
);
1003 item
->parent
= menu
;
1005 updateMenuContents(menu
);
1010 dragMenu(WEditMenu
*menu
)
1012 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1019 XGetGeometry(scr
->display
, W_VIEW_DRAWABLE(menu
->view
), &blaw
, &dx
, &dy
,
1020 &blau
, &blau
, &blau
, &blau
);
1021 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1022 scr
->rootWin
, dx
, dy
, &dx
, &dy
, &blaw
);
1023 dx
= menu
->dragX
- dx
;
1024 dy
= menu
->dragY
- dy
;
1026 XGrabPointer(scr
->display
, scr
->rootWin
, False
,
1027 ButtonReleaseMask
|ButtonMotionMask
,
1028 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1032 WMNextEvent(scr
->display
, &ev
);
1040 WMMoveWidget(menu
, ev
.xmotion
.x_root
- dx
,
1041 ev
.xmotion
.y_root
- dy
);
1050 XUngrabPointer(scr
->display
, CurrentTime
);
1056 dragItem(WEditMenu
*menu
, WEditMenuItem
*item
)
1058 Display
*dpy
= W_VIEW_DISPLAY(menu
->view
);
1059 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1069 Bool enteredMenu
= False
;
1070 WMSize oldSize
= item
->view
->size
;
1071 WEditMenu
*dmenu
= NULL
;
1074 if (item
->flags
.isTitle
) {
1075 WMRaiseWidget(menu
);
1083 selectItem(menu
, NULL
);
1085 assert(menu
->dropTargets
!= NULL
);
1090 XTranslateCoordinates(dpy
, W_VIEW_DRAWABLE(item
->view
), win
,
1091 0, 0, &orix
, &oriy
, &blaw
);
1093 dview
= W_CreateUnmanagedTopView(scr
);
1094 W_SetViewBackgroundColor(dview
, scr
->black
);
1095 W_ResizeView(dview
, W_VIEW_WIDTH(item
->view
), W_VIEW_HEIGHT(item
->view
));
1096 W_MoveView(dview
, orix
, oriy
);
1097 W_RealizeView(dview
);
1099 if (menu
->flags
.isFactory
) {
1100 WEditMenuItem
*nitem
;
1102 nitem
= WCreateEditMenuItem(menu
, item
->label
, False
);
1104 if (menu
->delegate
) {
1105 (*menu
->delegate
->itemCloned
)(menu
->delegate
, menu
, item
, nitem
);
1109 W_ReparentView(item
->view
, dview
, 0, 0);
1110 WMResizeWidget(item
, oldSize
.width
, oldSize
.height
);
1111 WMRealizeWidget(item
);
1114 W_ReparentView(item
->view
, dview
, 0, 0);
1119 dx
= menu
->dragX
- orix
;
1120 dy
= menu
->dragY
- oriy
;
1122 XGrabPointer(dpy
, scr
->rootWin
, False
,
1123 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
1124 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1130 WMNextEvent(dpy
, &ev
);
1134 XQueryPointer(dpy
, win
, &blaw
, &blaw
, &blai
, &blai
, &x
, &y
, &blau
);
1136 dmenu
= findMenuInWindow(dpy
, win
, x
, y
, menu
->dropTargets
);
1139 handleDragOver(dmenu
, dview
, item
, x
- dx
, y
- dy
);
1143 W_ResizeView(dview
, oldSize
.width
, oldSize
.height
);
1144 W_ResizeView(item
->view
, oldSize
.width
, oldSize
.height
);
1145 enteredMenu
= False
;
1147 W_MoveView(dview
, x
- dx
, y
- dy
);
1161 XUngrabPointer(dpy
, CurrentTime
);
1163 if (menu
->flags
.isFactory
&& !enteredMenu
) {
1164 slideWindow(dpy
, W_VIEW_DRAWABLE(dview
), x
-dx
, y
-dy
, orix
, oriy
);
1166 WRemoveEditMenuItem(menu
, item
);
1168 handleItemDrop(dmenu
, item
, x
-dy
, y
-dy
);
1172 /* can't destroy now because we're being called from
1173 * the event handler of the item. and destroying now,
1174 * would mean destroying the item too in some cases.
1176 WMAddIdleHandler((WMCallback
*)W_DestroyView
, dview
);
1182 handleItemClick(XEvent
*event
, void *data
)
1184 WEditMenuItem
*item
= (WEditMenuItem
*)data
;
1185 WEditMenu
*menu
= item
->parent
;
1187 switch (event
->type
) {
1189 selectItem(menu
, item
);
1191 if (WMIsDoubleClick(event
)) {
1192 editItemLabel(item
);
1195 menu
->flags
.isDragging
= 1;
1196 menu
->dragX
= event
->xbutton
.x_root
;
1197 menu
->dragY
= event
->xbutton
.y_root
;
1201 menu
->flags
.isDragging
= 0;
1205 if (menu
->flags
.isDragging
) {
1206 if (abs(event
->xbutton
.x_root
- menu
->dragX
) > 5
1207 || abs(event
->xbutton
.y_root
- menu
->dragY
) > 5) {
1208 menu
->flags
.isDragging
= 0;
1209 dragItem(menu
, item
);
1218 destroyEditMenu(WEditMenu
*mPtr
)
1220 WMRemoveNotificationObserver(mPtr
);
1222 WMFreeBag(mPtr
->items
);
1224 free(mPtr
->dropTargets
);