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,
24 #include <WINGs/WINGsP.h>
25 #include <WINGs/WUtil.h>
32 typedef struct W_EditMenuItem
{
36 struct W_EditMenu
*parent
;
39 WMPixmap
*pixmap
; /* pixmap to show at left */
42 WMCallback
*destroyData
;
44 struct W_EditMenu
*submenu
; /* if it's a cascade, NULL otherwise */
48 unsigned isHighlighted
:1;
53 typedef struct W_EditMenu
{
57 struct W_EditMenu
*parent
;
59 WMArray
*items
; /* EditMenuItem */
61 EditMenuItem
*selectedItem
;
70 WEditMenuDelegate
*delegate
;
72 WMTextFieldDelegate
*tdelegate
;
78 /* only for non-standalone menu */
83 unsigned standalone
:1;
86 unsigned acceptsDrop
:1;
88 unsigned isSelectable
:1;
89 unsigned isEditable
:1;
93 unsigned isDragging
:1;
102 /******************** WEditMenuItem ********************/
104 static void destroyEditMenuItem(WEditMenuItem
*iPtr
);
105 static void paintEditMenuItem(WEditMenuItem
*iPtr
);
106 static void handleItemEvents(XEvent
*event
, void *data
);
108 static void handleItemClick(XEvent
*event
, void *data
);
111 static W_Class EditMenuItemClass
= 0;
115 InitEditMenuItem(WMScreen
*scr
)
117 /* register our widget with WINGs and get our widget class ID */
118 if (!EditMenuItemClass
) {
119 EditMenuItemClass
= W_RegisterUserWidget();
122 return EditMenuItemClass
;
127 WCreateEditMenuItem(WMWidget
*parent
, char *title
, Bool isTitle
)
130 WMScreen
*scr
= WMWidgetScreen(parent
);
132 if (!EditMenuItemClass
)
133 InitEditMenuItem(scr
);
136 iPtr
= wmalloc(sizeof(WEditMenuItem
));
138 memset(iPtr
, 0, sizeof(WEditMenuItem
));
140 iPtr
->widgetClass
= EditMenuItemClass
;
142 iPtr
->view
= W_CreateView(W_VIEW(parent
));
147 iPtr
->view
->self
= iPtr
;
149 iPtr
->parent
= parent
;
151 iPtr
->label
= wstrdup(title
);
153 iPtr
->flags
.isTitle
= isTitle
;
156 WMSetWidgetBackgroundColor(iPtr
, WMBlackColor(scr
));
159 WMCreateEventHandler(iPtr
->view
, ExposureMask
|StructureNotifyMask
,
160 handleItemEvents
, iPtr
);
162 WMCreateEventHandler(iPtr
->view
, ButtonPressMask
|ButtonReleaseMask
163 |ButtonMotionMask
, handleItemClick
, iPtr
);
170 WGetEditMenuItemTitle(WEditMenuItem
*item
)
176 WGetEditMenuItemData(WEditMenuItem
*item
)
183 WSetEditMenuItemData(WEditMenuItem
*item
, void *data
, WMCallback
*destroyer
)
186 item
->destroyData
= destroyer
;
191 WSetEditMenuItemImage(WEditMenuItem
*item
, WMPixmap
*pixmap
)
194 WMReleasePixmap(item
->pixmap
);
195 item
->pixmap
= WMRetainPixmap(pixmap
);
200 paintEditMenuItem(WEditMenuItem
*iPtr
)
202 WMScreen
*scr
= WMWidgetScreen(iPtr
);
204 Window win
= W_VIEW(iPtr
)->window
;
205 int w
= W_VIEW(iPtr
)->size
.width
;
206 int h
= W_VIEW(iPtr
)->size
.height
;
207 WMFont
*font
= (iPtr
->flags
.isTitle
? scr
->boldFont
: scr
->normalFont
);
209 if (!iPtr
->view
->flags
.realized
)
213 if (iPtr
->flags
.isTitle
&& !iPtr
->flags
.isHighlighted
) {
218 XClearWindow(scr
->display
, win
);
220 W_DrawRelief(scr
, win
, 0, 0, w
+1, h
, WRRaised
);
222 WMDrawString(scr
, win
, WMColorGC(color
), font
, 5, 3, iPtr
->label
,
223 strlen(iPtr
->label
));
226 WMSize size
= WMGetPixmapSize(iPtr
->pixmap
);
228 WMDrawPixmap(iPtr
->pixmap
, win
, w
- size
.width
- 5,
229 (h
- size
.height
)/2);
230 } else if (iPtr
->submenu
) {
231 /* draw the cascade indicator */
232 XDrawLine(scr
->display
,win
,WMColorGC(scr
->darkGray
),
233 w
-11, 6, w
-6, h
/2-1);
234 XDrawLine(scr
->display
,win
,WMColorGC(scr
->white
),
235 w
-11, h
-8, w
-6, h
/2-1);
236 XDrawLine(scr
->display
,win
,WMColorGC(scr
->black
),
243 highlightItem(WEditMenuItem
*iPtr
, Bool high
)
245 if (iPtr
->flags
.isTitle
)
248 iPtr
->flags
.isHighlighted
= high
;
251 WMSetWidgetBackgroundColor(iPtr
, WMWhiteColor(WMWidgetScreen(iPtr
)));
253 if (!iPtr
->flags
.isTitle
) {
254 WMSetWidgetBackgroundColor(iPtr
,
255 WMGrayColor(WMWidgetScreen(iPtr
)));
257 WMSetWidgetBackgroundColor(iPtr
,
258 WMBlackColor(WMWidgetScreen(iPtr
)));
265 getItemTextWidth(WEditMenuItem
*iPtr
)
267 WMScreen
*scr
= WMWidgetScreen(iPtr
);
269 if (iPtr
->flags
.isTitle
) {
270 return WMWidthOfString(scr
->boldFont
, iPtr
->label
,
271 strlen(iPtr
->label
));
273 return WMWidthOfString(scr
->normalFont
, iPtr
->label
,
274 strlen(iPtr
->label
));
281 handleItemEvents(XEvent
*event
, void *data
)
283 WEditMenuItem
*iPtr
= (WEditMenuItem
*)data
;
285 switch (event
->type
) {
287 if (event
->xexpose
.count
!=0)
289 paintEditMenuItem(iPtr
);
293 destroyEditMenuItem(iPtr
);
300 destroyEditMenuItem(WEditMenuItem
*iPtr
)
304 if (iPtr
->data
&& iPtr
->destroyData
)
305 (*iPtr
->destroyData
)(iPtr
->data
);
307 WMDestroyWidget(iPtr
->submenu
);
314 /******************** WEditMenu *******************/
316 static void destroyEditMenu(WEditMenu
*mPtr
);
318 static void updateMenuContents(WEditMenu
*mPtr
);
320 static void handleEvents(XEvent
*event
, void *data
);
322 static void editItemLabel(WEditMenuItem
*item
);
324 static void stopEditItem(WEditMenu
*menu
, Bool apply
);
326 static void deselectItem(WEditMenu
*menu
);
329 static W_Class EditMenuClass
= 0;
333 InitEditMenu(WMScreen
*scr
)
335 /* register our widget with WINGs and get our widget class ID */
336 if (!EditMenuClass
) {
338 EditMenuClass
= W_RegisterUserWidget();
341 return EditMenuClass
;
351 Pixmap miniaturize_pixmap
; /* pixmap for miniaturize button */
352 Pixmap close_pixmap
; /* pixmap for close button */
353 Pixmap miniaturize_mask
; /* miniaturize pixmap mask */
354 Pixmap close_mask
; /* close pixmap mask */
356 } GNUstepWMAttributes
;
359 #define GSWindowStyleAttr (1<<0)
360 #define GSWindowLevelAttr (1<<1)
364 writeGNUstepWMAttr(WMScreen
*scr
, Window window
, GNUstepWMAttributes
*attr
)
366 unsigned long data
[9];
368 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
369 data
[0] = attr
->flags
;
370 data
[1] = attr
->window_style
;
371 data
[2] = attr
->window_level
;
372 data
[3] = 0; /* reserved */
373 /* The X protocol says XIDs are 32bit */
374 data
[4] = attr
->miniaturize_pixmap
;
375 data
[5] = attr
->close_pixmap
;
376 data
[6] = attr
->miniaturize_mask
;
377 data
[7] = attr
->close_mask
;
378 data
[8] = attr
->extra_flags
;
379 XChangeProperty(scr
->display
, window
, scr
->attribsAtom
, scr
->attribsAtom
,
380 32, PropModeReplace
, (unsigned char *)data
, 9);
385 realizeObserver(void *self
, WMNotification
*not)
387 WEditMenu
*menu
= (WEditMenu
*)self
;
388 GNUstepWMAttributes attribs
;
390 memset(&attribs
, 0, sizeof(GNUstepWMAttributes
));
391 attribs
.flags
= GSWindowStyleAttr
|GSWindowLevelAttr
;
392 attribs
.window_style
= WMBorderlessWindowMask
;
393 attribs
.window_level
= WMSubmenuWindowLevel
;
395 writeGNUstepWMAttr(WMWidgetScreen(menu
), menu
->view
->window
, &attribs
);
400 itemSelectObserver(void *self
, WMNotification
*notif
)
402 WEditMenu
*menu
= (WEditMenu
*)self
;
405 rmenu
= (WEditMenu
*)WMGetNotificationObject(notif
);
406 /* check whether rmenu is from the same hierarchy of menu? */
412 if (menu
->selectedItem
) {
413 if (!menu
->selectedItem
->submenu
)
415 if (menu
->flags
.isEditing
)
416 stopEditItem(menu
, False
);
422 makeEditMenu(WMScreen
*scr
, WMWidget
*parent
, char *title
)
431 mPtr
= wmalloc(sizeof(WEditMenu
));
432 memset(mPtr
, 0, sizeof(WEditMenu
));
434 mPtr
->widgetClass
= EditMenuClass
;
437 mPtr
->view
= W_CreateView(W_VIEW(parent
));
438 mPtr
->flags
.standalone
= 0;
440 mPtr
->view
= W_CreateTopView(scr
);
441 mPtr
->flags
.standalone
= 1;
447 mPtr
->view
->self
= mPtr
;
449 mPtr
->flags
.isSelectable
= 1;
450 mPtr
->flags
.isEditable
= 1;
452 W_SetViewBackgroundColor(mPtr
->view
, scr
->darkGray
);
454 WMAddNotificationObserver(realizeObserver
, mPtr
,
455 WMViewRealizedNotification
, mPtr
->view
);
457 WMAddNotificationObserver(itemSelectObserver
, mPtr
,
458 "EditMenuItemSelected", NULL
);
460 mPtr
->items
= WMCreateArray(4);
462 WMCreateEventHandler(mPtr
->view
, ExposureMask
|StructureNotifyMask
,
467 item
= WCreateEditMenuItem(mPtr
, title
, True
);
470 WMAddToArray(mPtr
->items
, item
);
472 mPtr
->flags
.isTitled
= 1;
475 mPtr
->itemHeight
= WMFontHeight(scr
->normalFont
) + 6;
476 mPtr
->titleHeight
= WMFontHeight(scr
->boldFont
) + 8;
478 updateMenuContents(mPtr
);
485 WCreateEditMenu(WMScreen
*scr
, char *title
)
487 return makeEditMenu(scr
, NULL
, title
);
492 WCreateEditMenuPad(WMWidget
*parent
)
494 return makeEditMenu(WMWidgetScreen(parent
), parent
, NULL
);
499 WSetEditMenuDelegate(WEditMenu
*mPtr
, WEditMenuDelegate
*delegate
)
501 mPtr
->delegate
= delegate
;
506 WInsertMenuItemWithTitle(WEditMenu
*mPtr
, int index
, char *title
)
510 item
= WCreateEditMenuItem(mPtr
, title
, False
);
514 if (index
>= WMGetArrayItemCount(mPtr
->items
)) {
515 WMAddToArray(mPtr
->items
, item
);
519 if (mPtr
->flags
.isTitled
)
521 WMInsertInArray(mPtr
->items
, index
, item
);
524 updateMenuContents(mPtr
);
531 WGetEditMenuItem(WEditMenu
*mPtr
, int index
)
533 if (index
>= WMGetArrayItemCount(mPtr
->items
))
536 return WMGetFromArray(mPtr
->items
, index
+ (mPtr
->flags
.isTitled
? 1 : 0));
541 WAddMenuItemWithTitle(WEditMenu
*mPtr
, char *title
)
543 return WInsertMenuItemWithTitle(mPtr
, WMGetArrayItemCount(mPtr
->items
),
550 WSetEditMenuTitle(WEditMenu
*mPtr
, char *title
)
554 item
= WMGetFromArray(mPtr
->items
, 0);
557 item
->label
= wstrdup(title
);
559 updateMenuContents(mPtr
);
561 WMRedisplayWidget(item
);
567 WGetEditMenuTitle(WEditMenu
*mPtr
)
571 item
= WMGetFromArray(mPtr
->items
, 0);
578 WSetEditMenuAcceptsDrop(WEditMenu
*mPtr
, Bool flag
)
580 mPtr
->flags
.acceptsDrop
= flag
;
585 WSetEditMenuSubmenu(WEditMenu
*mPtr
, WEditMenuItem
*item
, WEditMenu
*submenu
)
587 item
->submenu
= submenu
;
588 submenu
->parent
= mPtr
;
590 paintEditMenuItem(item
);
595 WGetEditMenuSubmenu(WEditMenu
*mPtr
, WEditMenuItem
*item
)
597 return item
->submenu
;
602 WRemoveEditMenuItem(WEditMenu
*mPtr
, WEditMenuItem
*item
)
604 if (WMRemoveFromArray(mPtr
->items
, item
) != 0) {
605 updateMenuContents(mPtr
);
611 WSetEditMenuSelectable(WEditMenu
*mPtr
, Bool flag
)
613 mPtr
->flags
.isSelectable
= flag
;
618 WSetEditMenuEditable(WEditMenu
*mPtr
, Bool flag
)
620 mPtr
->flags
.isEditable
= flag
;
625 WSetEditMenuIsFactory(WEditMenu
*mPtr
, Bool flag
)
627 mPtr
->flags
.isFactory
= flag
;
632 WSetEditMenuMinSize(WEditMenu
*mPtr
, WMSize size
)
634 mPtr
->minSize
.width
= size
.width
;
635 mPtr
->minSize
.height
= size
.height
;
640 WSetEditMenuMaxSize(WEditMenu
*mPtr
, WMSize size
)
642 mPtr
->maxSize
.width
= size
.width
;
643 mPtr
->maxSize
.height
= size
.height
;
648 WGetEditMenuLocationForSubmenu(WEditMenu
*mPtr
, WEditMenu
*submenu
)
650 WMArrayIterator iter
;
654 if (mPtr
->flags
.isTitled
)
655 y
= -mPtr
->titleHeight
;
658 WM_ITERATE_ARRAY(mPtr
->items
, item
, iter
) {
659 if (item
->submenu
== submenu
) {
660 WMPoint pt
= WMGetViewScreenPosition(mPtr
->view
);
662 return wmkpoint(pt
.x
+ mPtr
->view
->size
.width
, pt
.y
+ y
);
664 y
+= W_VIEW_HEIGHT(item
->view
);
667 puts("invalid submenu passed to WGetEditMenuLocationForSubmenu()");
669 return wmkpoint(0,0);
675 closeMenuAction(WMWidget
*w
, void *data
)
677 WEditMenu
*menu
= (WEditMenu
*)data
;
679 WMAddIdleHandler(WMDestroyWidget
, menu
->closeB
);
687 WTearOffEditMenu(WEditMenu
*menu
, WEditMenu
*submenu
)
691 submenu
->flags
.isTornOff
= 1;
693 item
= (WEditMenuItem
*)WMGetFromArray(submenu
->items
, 0);
695 submenu
->closeB
= WMCreateCommandButton(item
);
696 WMResizeWidget(submenu
->closeB
, 15, 15);
697 WMMoveWidget(submenu
->closeB
, W_VIEW(submenu
)->size
.width
- 20, 3);
698 WMRealizeWidget(submenu
->closeB
);
699 WMSetButtonText(submenu
->closeB
, "X");
700 WMSetButtonAction(submenu
->closeB
, closeMenuAction
, submenu
);
701 WMMapWidget(submenu
->closeB
);
703 if (menu
->selectedItem
&& menu
->selectedItem
->submenu
== submenu
)
710 WEditMenuIsTornOff(WEditMenu
*mPtr
)
712 return mPtr
->flags
.isTornOff
;
718 WEditMenuHide(WEditMenu
*mPtr
)
723 if (WMWidgetIsMapped(mPtr
)) {
725 mPtr
->flags
.wasMapped
= 1;
727 mPtr
->flags
.wasMapped
= 0;
729 while ((item
= WGetEditMenuItem(mPtr
, i
++))) {
732 submenu
= WGetEditMenuSubmenu(mPtr
, item
);
734 WEditMenuHide(submenu
);
742 WEditMenuUnhide(WEditMenu
*mPtr
)
747 if (mPtr
->flags
.wasMapped
) {
750 while ((item
= WGetEditMenuItem(mPtr
, i
++))) {
753 submenu
= WGetEditMenuSubmenu(mPtr
, item
);
755 WEditMenuUnhide(submenu
);
762 WEditMenuShowAt(WEditMenu
*menu
, int x
, int y
)
766 hints
= XAllocSizeHints();
768 hints
->flags
= USPosition
;
772 WMMoveWidget(menu
, x
, y
);
773 XSetWMNormalHints(W_VIEW_DISPLAY(menu
->view
),
774 W_VIEW_DRAWABLE(menu
->view
),
783 updateMenuContents(WEditMenu
*mPtr
)
788 int iheight
= mPtr
->itemHeight
;
790 WMArrayIterator iter
;
797 WM_ITERATE_ARRAY(mPtr
->items
, item
, iter
) {
798 w
= getItemTextWidth(item
);
800 newW
= WMAX(w
, newW
);
802 WMMoveWidget(item
, offs
, newH
);
803 if (i
== 0 && mPtr
->flags
.isTitled
) {
804 newH
+= mPtr
->titleHeight
;
811 newW
+= iheight
+ 10;
814 if (mPtr
->minSize
.width
)
815 newW
= WMAX(newW
, mPtr
->minSize
.width
);
816 if (mPtr
->maxSize
.width
)
817 newW
= WMIN(newW
, mPtr
->maxSize
.width
);
819 if (mPtr
->minSize
.height
)
820 newH
= WMAX(newH
, mPtr
->minSize
.height
);
821 if (mPtr
->maxSize
.height
)
822 newH
= WMIN(newH
, mPtr
->maxSize
.height
);
824 if (W_VIEW(mPtr
)->size
.width
== newW
&& mPtr
->view
->size
.height
== newH
+1)
827 W_ResizeView(mPtr
->view
, newW
, newH
+1);
830 WMMoveWidget(mPtr
->closeB
, newW
- 20, 3);
835 WM_ITERATE_ARRAY(mPtr
->items
, item
, iter
) {
836 if (i
== 0 && mPtr
->flags
.isTitled
) {
837 WMResizeWidget(item
, newW
, mPtr
->titleHeight
);
839 WMResizeWidget(item
, newW
, iheight
);
847 deselectItem(WEditMenu
*menu
)
850 WEditMenuItem
*item
= menu
->selectedItem
;
852 highlightItem(item
, False
);
854 if (menu
->delegate
&& menu
->delegate
->itemDeselected
) {
855 (*menu
->delegate
->itemDeselected
)(menu
->delegate
, menu
, item
);
857 submenu
= item
->submenu
;
859 if (submenu
&& !WEditMenuIsTornOff(submenu
)) {
860 WEditMenuHide(submenu
);
863 menu
->selectedItem
= NULL
;
868 selectItem(WEditMenu
*menu
, WEditMenuItem
*item
)
870 if (!menu
->flags
.isSelectable
|| menu
->selectedItem
== item
) {
873 if (menu
->selectedItem
) {
877 if (menu
->flags
.isEditing
) {
878 stopEditItem(menu
, False
);
881 if (item
&& !item
->flags
.isTitle
) {
882 highlightItem(item
, True
);
884 if (item
->submenu
&& !W_VIEW_MAPPED(item
->submenu
->view
)) {
887 pt
= WGetEditMenuLocationForSubmenu(menu
, item
->submenu
);
889 WEditMenuShowAt(item
->submenu
, pt
.x
, pt
.y
);
891 item
->submenu
->flags
.isTornOff
= 0;
894 WMPostNotificationName("EditMenuItemSelected", menu
, NULL
);
896 if (menu
->delegate
&& menu
->delegate
->itemSelected
) {
897 (*menu
->delegate
->itemSelected
)(menu
->delegate
, menu
, item
);
901 menu
->selectedItem
= item
;
906 paintMenu(WEditMenu
*mPtr
)
908 W_View
*view
= mPtr
->view
;
910 W_DrawRelief(W_VIEW_SCREEN(view
), W_VIEW_DRAWABLE(view
), 0, 0,
911 W_VIEW_WIDTH(view
), W_VIEW_HEIGHT(view
), WRSimple
);
916 handleEvents(XEvent
*event
, void *data
)
918 WEditMenu
*mPtr
= (WEditMenu
*)data
;
920 switch (event
->type
) {
922 destroyEditMenu(mPtr
);
926 if (event
->xexpose
.count
== 0)
935 /* -------------------------- Menu Label Editing ------------------------ */
939 stopEditItem(WEditMenu
*menu
, Bool apply
)
944 text
= WMGetTextFieldText(menu
->tfield
);
946 wfree(menu
->selectedItem
->label
);
947 menu
->selectedItem
->label
= wstrdup(text
);
949 updateMenuContents(menu
);
951 if (menu
->delegate
&& menu
->delegate
->itemEdited
) {
952 (*menu
->delegate
->itemEdited
)(menu
->delegate
, menu
,
957 WMUnmapWidget(menu
->tfield
);
958 menu
->flags
.isEditing
= 0;
963 textEndedEditing(struct WMTextFieldDelegate
*self
, WMNotification
*notif
)
965 WEditMenu
*menu
= (WEditMenu
*)self
->data
;
970 if (!menu
->flags
.isEditing
)
973 reason
= (int)WMGetNotificationClientData(notif
);
976 case WMEscapeTextMovement
:
977 stopEditItem(menu
, False
);
980 case WMReturnTextMovement
:
981 stopEditItem(menu
, True
);
984 case WMTabTextMovement
:
985 stopEditItem(menu
, True
);
987 i
= WMGetFirstInArray(menu
->items
, menu
->selectedItem
);
988 item
= WMGetFromArray(menu
->items
, i
+1);
990 selectItem(menu
, item
);
995 case WMBacktabTextMovement
:
996 stopEditItem(menu
, True
);
998 i
= WMGetFirstInArray(menu
->items
, menu
->selectedItem
);
999 item
= WMGetFromArray(menu
->items
, i
-1);
1001 selectItem(menu
, item
);
1002 editItemLabel(item
);
1010 static WMTextFieldDelegate textFieldDelegate
= {
1021 editItemLabel(WEditMenuItem
*item
)
1023 WEditMenu
*mPtr
= item
->parent
;
1026 if (!mPtr
->flags
.isEditable
) {
1030 if (!mPtr
->tfield
) {
1031 mPtr
->tfield
= WMCreateTextField(mPtr
);
1032 WMSetTextFieldBeveled(mPtr
->tfield
, False
);
1033 WMRealizeWidget(mPtr
->tfield
);
1035 mPtr
->tdelegate
= wmalloc(sizeof(WMTextFieldDelegate
));
1036 memcpy(mPtr
->tdelegate
, &textFieldDelegate
,
1037 sizeof(WMTextFieldDelegate
));
1039 mPtr
->tdelegate
->data
= mPtr
;
1041 WMSetTextFieldDelegate(mPtr
->tfield
, mPtr
->tdelegate
);
1045 WMSetTextFieldText(tf
, item
->label
);
1046 WMSelectTextFieldRange(tf
, wmkrange(0, strlen(item
->label
)));
1047 WMResizeWidget(tf
, mPtr
->view
->size
.width
, mPtr
->itemHeight
);
1048 WMMoveWidget(tf
, 0, item
->view
->pos
.y
);
1050 WMSetFocusToWidget(tf
);
1052 mPtr
->flags
.isEditing
= 1;
1057 /* -------------------------------------------------- */
1061 slideWindow(Display
*dpy
, Window win
, int srcX
, int srcY
, int dstX
, int dstY
)
1063 double x
, y
, dx
, dy
;
1067 iterations
= WMIN(25, WMAX(abs(dstX
-srcX
), abs(dstY
-srcY
)));
1072 dx
= (double)(dstX
-srcX
)/iterations
;
1073 dy
= (double)(dstY
-srcY
)/iterations
;
1075 for (i
= 0; i
<= iterations
; i
++) {
1076 XMoveWindow(dpy
, win
, x
, y
);
1088 errorHandler(Display
*d
, XErrorEvent
*ev
)
1096 findMenuInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
1104 int (*oldHandler
)(Display
*, XErrorEvent
*);
1106 view
= W_GetViewForXWindow(dpy
, toplevel
);
1107 if (view
&& view
->self
&& WMWidgetClass(view
->self
) == EditMenuClass
) {
1108 menu
= (WEditMenu
*)view
->self
;
1109 if (menu
->flags
.acceptsDrop
) {
1114 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
1115 &children
, &nchildren
) || children
== NULL
) {
1119 oldHandler
= XSetErrorHandler(errorHandler
);
1121 /* first window that contains the point is the one */
1122 for (i
= nchildren
-1; i
>= 0; i
--) {
1123 XWindowAttributes attr
;
1125 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
1126 && attr
.map_state
== IsViewable
1127 && x
>= attr
.x
&& y
>= attr
.y
1128 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
1133 menu
= findMenuInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
1141 XSetErrorHandler(oldHandler
);
1149 handleDragOver(WEditMenu
*menu
, WMView
*view
, WEditMenuItem
*item
,
1152 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1157 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1158 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
1160 offs
= menu
->flags
.standalone
? 0 : 1;
1162 W_MoveView(view
, mx
+ offs
, y
);
1163 if (view
->size
.width
!= menu
->view
->size
.width
) {
1164 W_ResizeView(view
, menu
->view
->size
.width
- 2*offs
,
1166 W_ResizeView(item
->view
, menu
->view
->size
.width
- 2*offs
,
1173 handleItemDrop(WEditMenu
*menu
, WEditMenuItem
*item
, int x
, int y
)
1175 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1180 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1181 scr
->rootWin
, 0, 0, &mx
, &my
, &blaw
);
1184 if (menu
->flags
.isTitled
) {
1185 index
-= menu
->titleHeight
;
1187 index
= (index
+ menu
->itemHeight
/2) / menu
->itemHeight
;
1191 if (menu
->flags
.isTitled
) {
1195 if (index
> WMGetArrayItemCount(menu
->items
)) {
1196 WMAddToArray(menu
->items
, item
);
1198 WMInsertInArray(menu
->items
, index
, item
);
1201 W_ReparentView(item
->view
, menu
->view
, 0, index
*menu
->itemHeight
);
1203 item
->parent
= menu
;
1204 if (item
->submenu
) {
1205 item
->submenu
->parent
= menu
;
1208 updateMenuContents(menu
);
1213 dragMenu(WEditMenu
*menu
)
1215 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1222 XGetGeometry(scr
->display
, W_VIEW_DRAWABLE(menu
->view
), &blaw
, &dx
, &dy
,
1223 &blau
, &blau
, &blau
, &blau
);
1225 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(menu
->view
),
1226 scr
->rootWin
, dx
, dy
, &dx
, &dy
, &blaw
);
1228 dx
= menu
->dragX
- dx
;
1229 dy
= menu
->dragY
- dy
;
1231 XGrabPointer(scr
->display
, scr
->rootWin
, False
,
1232 ButtonReleaseMask
|ButtonMotionMask
,
1233 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1237 WTearOffEditMenu(menu
->parent
, menu
);
1240 WMNextEvent(scr
->display
, &ev
);
1248 while (XCheckMaskEvent(scr
->display
, ButtonMotionMask
, &ev
)) ;
1250 WMMoveWidget(menu
, ev
.xmotion
.x_root
- dx
,
1251 ev
.xmotion
.y_root
- dy
);
1260 XUngrabPointer(scr
->display
, CurrentTime
);
1265 static WEditMenuItem
*
1266 duplicateItem(WEditMenuItem
*item
)
1268 WEditMenuItem
*nitem
;
1270 nitem
= WCreateEditMenuItem(item
->parent
, item
->label
, False
);
1272 nitem
->pixmap
= WMRetainPixmap(item
->pixmap
);
1281 duplicateMenu(WEditMenu
*menu
)
1284 WEditMenuItem
*item
;
1285 WMArrayIterator iter
;
1286 Bool first
= menu
->flags
.isTitled
;
1288 nmenu
= WCreateEditMenu(WMWidgetScreen(menu
), WGetEditMenuTitle(menu
));
1290 memcpy(&nmenu
->flags
, &menu
->flags
, sizeof(menu
->flags
));
1291 nmenu
->delegate
= menu
->delegate
;
1293 WM_ITERATE_ARRAY(menu
->items
, item
, iter
) {
1294 WEditMenuItem
*nitem
;
1301 nitem
= WAddMenuItemWithTitle(nmenu
, item
->label
);
1303 WSetEditMenuItemImage(nitem
, item
->pixmap
);
1305 if (menu
->delegate
&& menu
->delegate
->itemCloned
) {
1306 (*menu
->delegate
->itemCloned
)(menu
->delegate
, menu
,
1311 WMRealizeWidget(nmenu
);
1319 dragItem(WEditMenu
*menu
, WEditMenuItem
*item
, Bool copy
)
1321 static XColor black
= {0, 0,0,0, DoRed
|DoGreen
|DoBlue
};
1322 static XColor green
= {0x0045b045, 0x4500,0xb000,0x4500, DoRed
|DoGreen
|DoBlue
};
1323 static XColor back
= {0, 0xffff,0xffff,0xffff, DoRed
|DoGreen
|DoBlue
};
1324 Display
*dpy
= W_VIEW_DISPLAY(menu
->view
);
1325 WMScreen
*scr
= W_VIEW_SCREEN(menu
->view
);
1335 Bool enteredMenu
= False
;
1336 WMSize oldSize
= item
->view
->size
;
1337 WEditMenuItem
*dritem
= item
;
1338 WEditMenu
*dmenu
= NULL
;
1341 if (item
->flags
.isTitle
) {
1342 WMRaiseWidget(menu
);
1349 selectItem(menu
, NULL
);
1353 XTranslateCoordinates(dpy
, W_VIEW_DRAWABLE(item
->view
), win
,
1354 0, 0, &orix
, &oriy
, &blaw
);
1356 dview
= W_CreateUnmanagedTopView(scr
);
1357 W_SetViewBackgroundColor(dview
, scr
->black
);
1358 W_ResizeView(dview
, W_VIEW_WIDTH(item
->view
), W_VIEW_HEIGHT(item
->view
));
1359 W_MoveView(dview
, orix
, oriy
);
1360 W_RealizeView(dview
);
1362 if (menu
->flags
.isFactory
|| copy
) {
1363 dritem
= duplicateItem(item
);
1365 W_ReparentView(dritem
->view
, dview
, 0, 0);
1366 WMResizeWidget(dritem
, oldSize
.width
, oldSize
.height
);
1367 WMRealizeWidget(dritem
);
1368 WMMapWidget(dritem
);
1370 W_ReparentView(item
->view
, dview
, 0, 0);
1375 dx
= menu
->dragX
- orix
;
1376 dy
= menu
->dragY
- oriy
;
1378 XGrabPointer(dpy
, scr
->rootWin
, False
,
1379 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
1380 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
1383 if (menu
->flags
.acceptsDrop
)
1384 XRecolorCursor(dpy
, scr
->defaultCursor
, &green
, &back
);
1389 WMNextEvent(dpy
, &ev
);
1393 while (XCheckMaskEvent(dpy
, ButtonMotionMask
, &ev
)) ;
1395 XQueryPointer(dpy
, win
, &blaw
, &blaw
, &blai
, &blai
, &x
, &y
, &blau
);
1397 dmenu
= findMenuInWindow(dpy
, win
, x
, y
);
1400 handleDragOver(dmenu
, dview
, dritem
, x
- dx
, y
- dy
);
1403 XRecolorCursor(dpy
, scr
->defaultCursor
, &green
, &back
);
1407 W_ResizeView(dview
, oldSize
.width
, oldSize
.height
);
1408 W_ResizeView(dritem
->view
, oldSize
.width
, oldSize
.height
);
1409 enteredMenu
= False
;
1410 XRecolorCursor(dpy
, scr
->defaultCursor
, &black
, &back
);
1412 W_MoveView(dview
, x
- dx
, y
- dy
);
1426 XRecolorCursor(dpy
, scr
->defaultCursor
, &black
, &back
);
1428 XUngrabPointer(dpy
, CurrentTime
);
1434 if (!menu
->flags
.isFactory
&& !copy
) {
1436 if (menu
->delegate
&& menu
->delegate
->shouldRemoveItem
) {
1437 rem
= (*menu
->delegate
->shouldRemoveItem
)(menu
->delegate
,
1443 if (!rem
|| menu
->flags
.isFactory
|| copy
) {
1444 slideWindow(dpy
, W_VIEW_DRAWABLE(dview
), x
-dx
, y
-dy
, orix
, oriy
);
1446 if (!menu
->flags
.isFactory
&& !copy
) {
1447 WRemoveEditMenuItem(menu
, dritem
);
1448 handleItemDrop(dmenu
? dmenu
: menu
, dritem
, orix
, oriy
);
1451 WRemoveEditMenuItem(menu
, dritem
);
1454 WRemoveEditMenuItem(menu
, dritem
);
1456 if (menu
->delegate
&& menu
->delegate
->itemCloned
1457 && (menu
->flags
.isFactory
|| copy
)) {
1458 (*menu
->delegate
->itemCloned
)(menu
->delegate
, menu
,
1462 handleItemDrop(dmenu
, dritem
, x
-dy
, y
-dy
);
1464 if (item
->submenu
&& (menu
->flags
.isFactory
|| copy
)) {
1467 submenu
= duplicateMenu(item
->submenu
);
1468 WSetEditMenuSubmenu(dmenu
, dritem
, submenu
);
1472 /* can't destroy now because we're being called from
1473 * the event handler of the item. and destroying now,
1474 * would mean destroying the item too in some cases.
1476 WMAddIdleHandler((WMCallback
*)W_DestroyView
, dview
);
1482 handleItemClick(XEvent
*event
, void *data
)
1484 WEditMenuItem
*item
= (WEditMenuItem
*)data
;
1485 WEditMenu
*menu
= item
->parent
;
1487 switch (event
->type
) {
1489 selectItem(menu
, item
);
1491 if (WMIsDoubleClick(event
)) {
1492 editItemLabel(item
);
1495 menu
->flags
.isDragging
= 1;
1496 menu
->dragX
= event
->xbutton
.x_root
;
1497 menu
->dragY
= event
->xbutton
.y_root
;
1501 menu
->flags
.isDragging
= 0;
1505 if (menu
->flags
.isDragging
) {
1506 if (abs(event
->xbutton
.x_root
- menu
->dragX
) > 5
1507 || abs(event
->xbutton
.y_root
- menu
->dragY
) > 5) {
1508 menu
->flags
.isDragging
= 0;
1509 dragItem(menu
, item
, event
->xbutton
.state
& ControlMask
);
1518 destroyEditMenu(WEditMenu
*mPtr
)
1520 WEditMenuItem
*item
;
1521 WMArrayIterator iter
;
1523 WMRemoveNotificationObserver(mPtr
);
1525 WM_ITERATE_ARRAY(mPtr
->items
, item
, iter
) {
1526 if (item
->submenu
) {
1527 WMDestroyWidget(item
->submenu
);
1531 WMFreeArray(mPtr
->items
);
1533 wfree(mPtr
->tdelegate
);