1
/* editmenu.c - editable menus
3
* WPrefs - Window Maker Preferences Program
5
* Copyright (c) 2000-2003 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, color, font, 5, 3, iPtr->label, strlen(iPtr->label));
225
WMSize size = WMGetPixmapSize(iPtr->pixmap);
227
WMDrawPixmap(iPtr->pixmap, win, w - size.width - 5,
228
(h - size.height)/2);
229
} else if (iPtr->submenu) {
230
/* draw the cascade indicator */
231
XDrawLine(scr->display,win,WMColorGC(scr->darkGray),
232
w-11, 6, w-6, h/2-1);
233
XDrawLine(scr->display,win,WMColorGC(scr->white),
234
w-11, h-8, w-6, h/2-1);
235
XDrawLine(scr->display,win,WMColorGC(scr->black),
242
highlightItem(WEditMenuItem *iPtr, Bool high)
244
if (iPtr->flags.isTitle)
247
iPtr->flags.isHighlighted = high;
250
WMSetWidgetBackgroundColor(iPtr, WMWhiteColor(WMWidgetScreen(iPtr)));
252
if (!iPtr->flags.isTitle) {
253
WMSetWidgetBackgroundColor(iPtr,
254
WMGrayColor(WMWidgetScreen(iPtr)));
256
WMSetWidgetBackgroundColor(iPtr,
257
WMBlackColor(WMWidgetScreen(iPtr)));
264
getItemTextWidth(WEditMenuItem *iPtr)
266
WMScreen *scr = WMWidgetScreen(iPtr);
268
if (iPtr->flags.isTitle) {
269
return WMWidthOfString(scr->boldFont, iPtr->label,
270
strlen(iPtr->label));
272
return WMWidthOfString(scr->normalFont, iPtr->label,
273
strlen(iPtr->label));
280
handleItemEvents(XEvent *event, void *data)
282
WEditMenuItem *iPtr = (WEditMenuItem*)data;
284
switch (event->type) {
286
if (event->xexpose.count!=0)
288
paintEditMenuItem(iPtr);
292
destroyEditMenuItem(iPtr);
299
destroyEditMenuItem(WEditMenuItem *iPtr)
303
if (iPtr->data && iPtr->destroyData)
304
(*iPtr->destroyData)(iPtr->data);
306
WMDestroyWidget(iPtr->submenu);
313
/******************** WEditMenu *******************/
315
static void destroyEditMenu(WEditMenu *mPtr);
317
static void updateMenuContents(WEditMenu *mPtr);
319
static void handleEvents(XEvent *event, void *data);
321
static void editItemLabel(WEditMenuItem *item);
323
static void stopEditItem(WEditMenu *menu, Bool apply);
325
static void deselectItem(WEditMenu *menu);
328
static W_Class EditMenuClass = 0;
332
InitEditMenu(WMScreen *scr)
334
/* register our widget with WINGs and get our widget class ID */
335
if (!EditMenuClass) {
337
EditMenuClass = W_RegisterUserWidget();
340
return EditMenuClass;
350
Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
351
Pixmap close_pixmap; /* pixmap for close button */
352
Pixmap miniaturize_mask; /* miniaturize pixmap mask */
353
Pixmap close_mask; /* close pixmap mask */
355
} GNUstepWMAttributes;
358
#define GSWindowStyleAttr (1<<0)
359
#define GSWindowLevelAttr (1<<1)
363
writeGNUstepWMAttr(WMScreen *scr, Window window, GNUstepWMAttributes *attr)
365
unsigned long data[9];
367
/* handle idiot compilers where array of CARD32 != struct of CARD32 */
368
data[0] = attr->flags;
369
data[1] = attr->window_style;
370
data[2] = attr->window_level;
371
data[3] = 0; /* reserved */
372
/* The X protocol says XIDs are 32bit */
373
data[4] = attr->miniaturize_pixmap;
374
data[5] = attr->close_pixmap;
375
data[6] = attr->miniaturize_mask;
376
data[7] = attr->close_mask;
377
data[8] = attr->extra_flags;
378
XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
379
32, PropModeReplace, (unsigned char *)data, 9);
384
realizeObserver(void *self, WMNotification *not)
386
WEditMenu *menu = (WEditMenu*)self;
387
GNUstepWMAttributes attribs;
389
memset(&attribs, 0, sizeof(GNUstepWMAttributes));
390
attribs.flags = GSWindowStyleAttr|GSWindowLevelAttr;
391
attribs.window_style = WMBorderlessWindowMask;
392
attribs.window_level = WMSubmenuWindowLevel;
394
writeGNUstepWMAttr(WMWidgetScreen(menu), menu->view->window, &attribs);
399
itemSelectObserver(void *self, WMNotification *notif)
401
WEditMenu *menu = (WEditMenu*)self;
404
rmenu = (WEditMenu*)WMGetNotificationObject(notif);
405
/* check whether rmenu is from the same hierarchy of menu? */
411
if (menu->selectedItem) {
412
if (!menu->selectedItem->submenu)
414
if (menu->flags.isEditing)
415
stopEditItem(menu, False);
421
makeEditMenu(WMScreen *scr, WMWidget *parent, char *title)
430
mPtr = wmalloc(sizeof(WEditMenu));
431
memset(mPtr, 0, sizeof(WEditMenu));
433
mPtr->widgetClass = EditMenuClass;
436
mPtr->view = W_CreateView(W_VIEW(parent));
437
mPtr->flags.standalone = 0;
439
mPtr->view = W_CreateTopView(scr);
440
mPtr->flags.standalone = 1;
446
mPtr->view->self = mPtr;
448
mPtr->flags.isSelectable = 1;
449
mPtr->flags.isEditable = 1;
451
W_SetViewBackgroundColor(mPtr->view, scr->darkGray);
453
WMAddNotificationObserver(realizeObserver, mPtr,
454
WMViewRealizedNotification, mPtr->view);
456
WMAddNotificationObserver(itemSelectObserver, mPtr,
457
"EditMenuItemSelected", NULL);
459
mPtr->items = WMCreateArray(4);
461
WMCreateEventHandler(mPtr->view, ExposureMask|StructureNotifyMask,
466
item = WCreateEditMenuItem(mPtr, title, True);
469
WMAddToArray(mPtr->items, item);
471
mPtr->flags.isTitled = 1;
474
mPtr->itemHeight = WMFontHeight(scr->normalFont) + 6;
475
mPtr->titleHeight = WMFontHeight(scr->boldFont) + 8;
477
updateMenuContents(mPtr);
484
WCreateEditMenu(WMScreen *scr, char *title)
486
return makeEditMenu(scr, NULL, title);
491
WCreateEditMenuPad(WMWidget *parent)
493
return makeEditMenu(WMWidgetScreen(parent), parent, NULL);
498
WSetEditMenuDelegate(WEditMenu *mPtr, WEditMenuDelegate *delegate)
500
mPtr->delegate = delegate;
505
WInsertMenuItemWithTitle(WEditMenu *mPtr, int index, char *title)
509
item = WCreateEditMenuItem(mPtr, title, False);
513
if (index >= WMGetArrayItemCount(mPtr->items)) {
514
WMAddToArray(mPtr->items, item);
518
if (mPtr->flags.isTitled)
520
WMInsertInArray(mPtr->items, index, item);
523
updateMenuContents(mPtr);
530
WGetEditMenuItem(WEditMenu *mPtr, int index)
532
if (index >= WMGetArrayItemCount(mPtr->items))
535
return WMGetFromArray(mPtr->items, index + (mPtr->flags.isTitled ? 1 : 0));
540
WAddMenuItemWithTitle(WEditMenu *mPtr, char *title)
542
return WInsertMenuItemWithTitle(mPtr, WMGetArrayItemCount(mPtr->items),
549
WSetEditMenuTitle(WEditMenu *mPtr, char *title)
553
item = WMGetFromArray(mPtr->items, 0);
556
item->label = wstrdup(title);
558
updateMenuContents(mPtr);
560
WMRedisplayWidget(item);
566
WGetEditMenuTitle(WEditMenu *mPtr)
570
item = WMGetFromArray(mPtr->items, 0);
577
WSetEditMenuAcceptsDrop(WEditMenu *mPtr, Bool flag)
579
mPtr->flags.acceptsDrop = flag;
584
WSetEditMenuSubmenu(WEditMenu *mPtr, WEditMenuItem *item, WEditMenu *submenu)
586
item->submenu = submenu;
587
submenu->parent = mPtr;
589
paintEditMenuItem(item);
594
WGetEditMenuSubmenu(WEditMenu *mPtr, WEditMenuItem *item)
596
return item->submenu;
601
WRemoveEditMenuItem(WEditMenu *mPtr, WEditMenuItem *item)
603
if (WMRemoveFromArray(mPtr->items, item) != 0) {
604
updateMenuContents(mPtr);
610
WSetEditMenuSelectable(WEditMenu *mPtr, Bool flag)
612
mPtr->flags.isSelectable = flag;
617
WSetEditMenuEditable(WEditMenu *mPtr, Bool flag)
619
mPtr->flags.isEditable = flag;
624
WSetEditMenuIsFactory(WEditMenu *mPtr, Bool flag)
626
mPtr->flags.isFactory = flag;
631
WSetEditMenuMinSize(WEditMenu *mPtr, WMSize size)
633
mPtr->minSize.width = size.width;
634
mPtr->minSize.height = size.height;
639
WSetEditMenuMaxSize(WEditMenu *mPtr, WMSize size)
641
mPtr->maxSize.width = size.width;
642
mPtr->maxSize.height = size.height;
647
WGetEditMenuLocationForSubmenu(WEditMenu *mPtr, WEditMenu *submenu)
649
WMArrayIterator iter;
653
if (mPtr->flags.isTitled)
654
y = -mPtr->titleHeight;
657
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
658
if (item->submenu == submenu) {
659
WMPoint pt = WMGetViewScreenPosition(mPtr->view);
661
return wmkpoint(pt.x + mPtr->view->size.width, pt.y + y);
663
y += W_VIEW_HEIGHT(item->view);
666
puts("invalid submenu passed to WGetEditMenuLocationForSubmenu()");
668
return wmkpoint(0,0);
674
closeMenuAction(WMWidget *w, void *data)
676
WEditMenu *menu = (WEditMenu*)data;
678
WMAddIdleHandler(WMDestroyWidget, menu->closeB);
686
WTearOffEditMenu(WEditMenu *menu, WEditMenu *submenu)
690
submenu->flags.isTornOff = 1;
692
item = (WEditMenuItem*)WMGetFromArray(submenu->items, 0);
694
submenu->closeB = WMCreateCommandButton(item);
695
WMResizeWidget(submenu->closeB, 15, 15);
696
WMMoveWidget(submenu->closeB, W_VIEW(submenu)->size.width - 20, 3);
697
WMRealizeWidget(submenu->closeB);
698
WMSetButtonText(submenu->closeB, "X");
699
WMSetButtonAction(submenu->closeB, closeMenuAction, submenu);
700
WMMapWidget(submenu->closeB);
702
if (menu->selectedItem && menu->selectedItem->submenu == submenu)
709
WEditMenuIsTornOff(WEditMenu *mPtr)
711
return mPtr->flags.isTornOff;
717
WEditMenuHide(WEditMenu *mPtr)
722
if (WMWidgetIsMapped(mPtr)) {
724
mPtr->flags.wasMapped = 1;
726
mPtr->flags.wasMapped = 0;
728
while ((item = WGetEditMenuItem(mPtr, i++))) {
731
submenu = WGetEditMenuSubmenu(mPtr, item);
733
WEditMenuHide(submenu);
741
WEditMenuUnhide(WEditMenu *mPtr)
746
if (mPtr->flags.wasMapped) {
749
while ((item = WGetEditMenuItem(mPtr, i++))) {
752
submenu = WGetEditMenuSubmenu(mPtr, item);
754
WEditMenuUnhide(submenu);
761
WEditMenuShowAt(WEditMenu *menu, int x, int y)
765
hints = XAllocSizeHints();
767
hints->flags = USPosition;
771
WMMoveWidget(menu, x, y);
772
XSetWMNormalHints(W_VIEW_DISPLAY(menu->view),
773
W_VIEW_DRAWABLE(menu->view),
782
updateMenuContents(WEditMenu *mPtr)
787
int iheight = mPtr->itemHeight;
789
WMArrayIterator iter;
796
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
797
w = getItemTextWidth(item);
799
newW = WMAX(w, newW);
801
WMMoveWidget(item, offs, newH);
802
if (i == 0 && mPtr->flags.isTitled) {
803
newH += mPtr->titleHeight;
810
newW += iheight + 10;
813
if (mPtr->minSize.width)
814
newW = WMAX(newW, mPtr->minSize.width);
815
if (mPtr->maxSize.width)
816
newW = WMIN(newW, mPtr->maxSize.width);
818
if (mPtr->minSize.height)
819
newH = WMAX(newH, mPtr->minSize.height);
820
if (mPtr->maxSize.height)
821
newH = WMIN(newH, mPtr->maxSize.height);
823
if (W_VIEW(mPtr)->size.width == newW && mPtr->view->size.height == newH+1)
826
W_ResizeView(mPtr->view, newW, newH+1);
829
WMMoveWidget(mPtr->closeB, newW - 20, 3);
834
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
835
if (i == 0 && mPtr->flags.isTitled) {
836
WMResizeWidget(item, newW, mPtr->titleHeight);
838
WMResizeWidget(item, newW, iheight);
846
deselectItem(WEditMenu *menu)
849
WEditMenuItem *item = menu->selectedItem;
851
highlightItem(item, False);
853
if (menu->delegate && menu->delegate->itemDeselected) {
854
(*menu->delegate->itemDeselected)(menu->delegate, menu, item);
856
submenu = item->submenu;
858
if (submenu && !WEditMenuIsTornOff(submenu)) {
859
WEditMenuHide(submenu);
862
menu->selectedItem = NULL;
867
selectItem(WEditMenu *menu, WEditMenuItem *item)
869
if (!menu->flags.isSelectable || menu->selectedItem == item) {
872
if (menu->selectedItem) {
876
if (menu->flags.isEditing) {
877
stopEditItem(menu, False);
880
if (item && !item->flags.isTitle) {
881
highlightItem(item, True);
883
if (item->submenu && !W_VIEW_MAPPED(item->submenu->view)) {
886
pt = WGetEditMenuLocationForSubmenu(menu, item->submenu);
888
WEditMenuShowAt(item->submenu, pt.x, pt.y);
890
item->submenu->flags.isTornOff = 0;
893
WMPostNotificationName("EditMenuItemSelected", menu, NULL);
895
if (menu->delegate && menu->delegate->itemSelected) {
896
(*menu->delegate->itemSelected)(menu->delegate, menu, item);
900
menu->selectedItem = item;
905
paintMenu(WEditMenu *mPtr)
907
W_View *view = mPtr->view;
909
W_DrawRelief(W_VIEW_SCREEN(view), W_VIEW_DRAWABLE(view), 0, 0,
910
W_VIEW_WIDTH(view), W_VIEW_HEIGHT(view), WRSimple);
915
handleEvents(XEvent *event, void *data)
917
WEditMenu *mPtr = (WEditMenu*)data;
919
switch (event->type) {
921
destroyEditMenu(mPtr);
925
if (event->xexpose.count == 0)
934
/* -------------------------- Menu Label Editing ------------------------ */
938
stopEditItem(WEditMenu *menu, Bool apply)
943
text = WMGetTextFieldText(menu->tfield);
945
wfree(menu->selectedItem->label);
946
menu->selectedItem->label = wstrdup(text);
948
updateMenuContents(menu);
950
if (menu->delegate && menu->delegate->itemEdited) {
951
(*menu->delegate->itemEdited)(menu->delegate, menu,
956
WMUnmapWidget(menu->tfield);
957
menu->flags.isEditing = 0;
962
textEndedEditing(struct WMTextFieldDelegate *self, WMNotification *notif)
964
WEditMenu *menu = (WEditMenu*)self->data;
969
if (!menu->flags.isEditing)
972
reason = (int)WMGetNotificationClientData(notif);
975
case WMEscapeTextMovement:
976
stopEditItem(menu, False);
979
case WMReturnTextMovement:
980
stopEditItem(menu, True);
983
case WMTabTextMovement:
984
stopEditItem(menu, True);
986
i = WMGetFirstInArray(menu->items, menu->selectedItem);
987
item = WMGetFromArray(menu->items, i+1);
989
selectItem(menu, item);
994
case WMBacktabTextMovement:
995
stopEditItem(menu, True);
997
i = WMGetFirstInArray(menu->items, menu->selectedItem);
998
item = WMGetFromArray(menu->items, i-1);
1000
selectItem(menu, item);
1001
editItemLabel(item);
1009
static WMTextFieldDelegate textFieldDelegate = {
1020
editItemLabel(WEditMenuItem *item)
1022
WEditMenu *mPtr = item->parent;
1025
if (!mPtr->flags.isEditable) {
1029
if (!mPtr->tfield) {
1030
mPtr->tfield = WMCreateTextField(mPtr);
1031
WMSetTextFieldBeveled(mPtr->tfield, False);
1032
WMRealizeWidget(mPtr->tfield);
1034
mPtr->tdelegate = wmalloc(sizeof(WMTextFieldDelegate));
1035
memcpy(mPtr->tdelegate, &textFieldDelegate,
1036
sizeof(WMTextFieldDelegate));
1038
mPtr->tdelegate->data = mPtr;
1040
WMSetTextFieldDelegate(mPtr->tfield, mPtr->tdelegate);
1044
WMSetTextFieldText(tf, item->label);
1045
WMSelectTextFieldRange(tf, wmkrange(0, strlen(item->label)));
1046
WMResizeWidget(tf, mPtr->view->size.width, mPtr->itemHeight);
1047
WMMoveWidget(tf, 0, item->view->pos.y);
1049
WMSetFocusToWidget(tf);
1051
mPtr->flags.isEditing = 1;
1056
/* -------------------------------------------------- */
1060
slideWindow(Display *dpy, Window win, int srcX, int srcY, int dstX, int dstY)
1062
double x, y, dx, dy;
1066
iterations = WMIN(25, WMAX(abs(dstX-srcX), abs(dstY-srcY)));
1071
dx = (double)(dstX-srcX)/iterations;
1072
dy = (double)(dstY-srcY)/iterations;
1074
for (i = 0; i <= iterations; i++) {
1075
XMoveWindow(dpy, win, x, y);
1087
errorHandler(Display *d, XErrorEvent *ev)
1095
findMenuInWindow(Display *dpy, Window toplevel, int x, int y)
1103
int (*oldHandler)(Display *, XErrorEvent *);
1105
view = W_GetViewForXWindow(dpy, toplevel);
1106
if (view && view->self && WMWidgetClass(view->self) == EditMenuClass) {
1107
menu = (WEditMenu*)view->self;
1108
if (menu->flags.acceptsDrop) {
1113
if (!XQueryTree(dpy, toplevel, &foo, &bar,
1114
&children, &nchildren) || children == NULL) {
1118
oldHandler = XSetErrorHandler(errorHandler);
1120
/* first window that contains the point is the one */
1121
for (i = nchildren-1; i >= 0; i--) {
1122
XWindowAttributes attr;
1124
if (XGetWindowAttributes(dpy, children[i], &attr)
1125
&& attr.map_state == IsViewable
1126
&& x >= attr.x && y >= attr.y
1127
&& x < attr.x + attr.width && y < attr.y + attr.height) {
1132
menu = findMenuInWindow(dpy, tmp, x - attr.x, y - attr.y);
1140
XSetErrorHandler(oldHandler);
1148
handleDragOver(WEditMenu *menu, WMView *view, WEditMenuItem *item,
1151
WMScreen *scr = W_VIEW_SCREEN(menu->view);
1156
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view),
1157
scr->rootWin, 0, 0, &mx, &my, &blaw);
1159
offs = menu->flags.standalone ? 0 : 1;
1161
W_MoveView(view, mx + offs, y);
1162
if (view->size.width != menu->view->size.width) {
1163
W_ResizeView(view, menu->view->size.width - 2*offs,
1165
W_ResizeView(item->view, menu->view->size.width - 2*offs,
1172
handleItemDrop(WEditMenu *menu, WEditMenuItem *item, int x, int y)
1174
WMScreen *scr = W_VIEW_SCREEN(menu->view);
1179
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view),
1180
scr->rootWin, 0, 0, &mx, &my, &blaw);
1183
if (menu->flags.isTitled) {
1184
index -= menu->titleHeight;
1186
index = (index + menu->itemHeight/2) / menu->itemHeight;
1190
if (menu->flags.isTitled) {
1194
if (index > WMGetArrayItemCount(menu->items)) {
1195
WMAddToArray(menu->items, item);
1197
WMInsertInArray(menu->items, index, item);
1200
W_ReparentView(item->view, menu->view, 0, index*menu->itemHeight);
1202
item->parent = menu;
1203
if (item->submenu) {
1204
item->submenu->parent = menu;
1207
updateMenuContents(menu);
1212
dragMenu(WEditMenu *menu)
1214
WMScreen *scr = W_VIEW_SCREEN(menu->view);
1221
XGetGeometry(scr->display, W_VIEW_DRAWABLE(menu->view), &blaw, &dx, &dy,
1222
&blau, &blau, &blau, &blau);
1224
XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(menu->view),
1225
scr->rootWin, dx, dy, &dx, &dy, &blaw);
1227
dx = menu->dragX - dx;
1228
dy = menu->dragY - dy;
1230
XGrabPointer(scr->display, scr->rootWin, False,
1231
ButtonReleaseMask|ButtonMotionMask,
1232
GrabModeAsync, GrabModeAsync, None, scr->defaultCursor,
1236
WTearOffEditMenu(menu->parent, menu);
1239
WMNextEvent(scr->display, &ev);
1247
while (XCheckMaskEvent(scr->display, ButtonMotionMask, &ev)) ;
1249
WMMoveWidget(menu, ev.xmotion.x_root - dx,
1250
ev.xmotion.y_root - dy);
1259
XUngrabPointer(scr->display, CurrentTime);
1264
static WEditMenuItem*
1265
duplicateItem(WEditMenuItem *item)
1267
WEditMenuItem *nitem;
1269
nitem = WCreateEditMenuItem(item->parent, item->label, False);
1271
nitem->pixmap = WMRetainPixmap(item->pixmap);
1280
duplicateMenu(WEditMenu *menu)
1283
WEditMenuItem *item;
1284
WMArrayIterator iter;
1285
Bool first = menu->flags.isTitled;
1287
nmenu = WCreateEditMenu(WMWidgetScreen(menu), WGetEditMenuTitle(menu));
1289
memcpy(&nmenu->flags, &menu->flags, sizeof(menu->flags));
1290
nmenu->delegate = menu->delegate;
1292
WM_ITERATE_ARRAY(menu->items, item, iter) {
1293
WEditMenuItem *nitem;
1300
nitem = WAddMenuItemWithTitle(nmenu, item->label);
1302
WSetEditMenuItemImage(nitem, item->pixmap);
1304
if (menu->delegate && menu->delegate->itemCloned) {
1305
(*menu->delegate->itemCloned)(menu->delegate, menu,
1310
WMRealizeWidget(nmenu);
1318
dragItem(WEditMenu *menu, WEditMenuItem *item, Bool copy)
1320
static XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};
1321
static XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};
1322
static XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};
1323
Display *dpy = W_VIEW_DISPLAY(menu->view);
1324
WMScreen *scr = W_VIEW_SCREEN(menu->view);
1334
Bool enteredMenu = False;
1335
WMSize oldSize = item->view->size;
1336
WEditMenuItem *dritem = item;
1337
WEditMenu *dmenu = NULL;
1340
if (item->flags.isTitle) {
1341
WMRaiseWidget(menu);
1348
selectItem(menu, NULL);
1352
XTranslateCoordinates(dpy, W_VIEW_DRAWABLE(item->view), win,
1353
0, 0, &orix, &oriy, &blaw);
1355
dview = W_CreateUnmanagedTopView(scr);
1356
W_SetViewBackgroundColor(dview, scr->black);
1357
W_ResizeView(dview, W_VIEW_WIDTH(item->view), W_VIEW_HEIGHT(item->view));
1358
W_MoveView(dview, orix, oriy);
1359
W_RealizeView(dview);
1361
if (menu->flags.isFactory || copy) {
1362
dritem = duplicateItem(item);
1364
W_ReparentView(dritem->view, dview, 0, 0);
1365
WMResizeWidget(dritem, oldSize.width, oldSize.height);
1366
WMRealizeWidget(dritem);
1367
WMMapWidget(dritem);
1369
W_ReparentView(item->view, dview, 0, 0);
1374
dx = menu->dragX - orix;
1375
dy = menu->dragY - oriy;
1377
XGrabPointer(dpy, scr->rootWin, False,
1378
ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
1379
GrabModeAsync, GrabModeAsync, None, scr->defaultCursor,
1382
if (menu->flags.acceptsDrop)
1383
XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
1388
WMNextEvent(dpy, &ev);
1392
while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
1394
XQueryPointer(dpy, win, &blaw, &blaw, &blai, &blai, &x, &y, &blau);
1396
dmenu = findMenuInWindow(dpy, win, x, y);
1399
handleDragOver(dmenu, dview, dritem, x - dx, y - dy);
1402
XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
1406
W_ResizeView(dview, oldSize.width, oldSize.height);
1407
W_ResizeView(dritem->view, oldSize.width, oldSize.height);
1408
enteredMenu = False;
1409
XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
1411
W_MoveView(dview, x - dx, y - dy);
1425
XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
1427
XUngrabPointer(dpy, CurrentTime);
1433
if (!menu->flags.isFactory && !copy) {
1435
if (menu->delegate && menu->delegate->shouldRemoveItem) {
1436
rem = (*menu->delegate->shouldRemoveItem)(menu->delegate,
1442
if (!rem || menu->flags.isFactory || copy) {
1443
slideWindow(dpy, W_VIEW_DRAWABLE(dview), x-dx, y-dy, orix, oriy);
1445
if (!menu->flags.isFactory && !copy) {
1446
WRemoveEditMenuItem(menu, dritem);
1447
handleItemDrop(dmenu ? dmenu : menu, dritem, orix, oriy);
1450
WRemoveEditMenuItem(menu, dritem);
1453
WRemoveEditMenuItem(menu, dritem);
1455
if (menu->delegate && menu->delegate->itemCloned
1456
&& (menu->flags.isFactory || copy)) {
1457
(*menu->delegate->itemCloned)(menu->delegate, menu,
1461
handleItemDrop(dmenu, dritem, x-dy, y-dy);
1463
if (item->submenu && (menu->flags.isFactory || copy)) {
1466
submenu = duplicateMenu(item->submenu);
1467
WSetEditMenuSubmenu(dmenu, dritem, submenu);
1471
/* can't destroy now because we're being called from
1472
* the event handler of the item. and destroying now,
1473
* would mean destroying the item too in some cases.
1475
WMAddIdleHandler((WMCallback*)W_DestroyView, dview);
1481
handleItemClick(XEvent *event, void *data)
1483
WEditMenuItem *item = (WEditMenuItem*)data;
1484
WEditMenu *menu = item->parent;
1486
switch (event->type) {
1488
selectItem(menu, item);
1490
if (WMIsDoubleClick(event)) {
1491
editItemLabel(item);
1494
menu->flags.isDragging = 1;
1495
menu->dragX = event->xbutton.x_root;
1496
menu->dragY = event->xbutton.y_root;
1500
menu->flags.isDragging = 0;
1504
if (menu->flags.isDragging) {
1505
if (abs(event->xbutton.x_root - menu->dragX) > 5
1506
|| abs(event->xbutton.y_root - menu->dragY) > 5) {
1507
menu->flags.isDragging = 0;
1508
dragItem(menu, item, event->xbutton.state & ControlMask);
1517
destroyEditMenu(WEditMenu *mPtr)
1519
WEditMenuItem *item;
1520
WMArrayIterator iter;
1522
WMRemoveNotificationObserver(mPtr);
1524
WM_ITERATE_ARRAY(mPtr->items, item, iter) {
1525
if (item->submenu) {
1526
WMDestroyWidget(item->submenu);
1530
WMFreeArray(mPtr->items);
1532
wfree(mPtr->tdelegate);