WINGs: Better presentation for example code in the tutorial
[whome.git] / WINGs_tutorial / WINGMenu.html
blob45d6a8287ef981edf224116a691e1fc1172f944a
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2 <!-- saved from url=(0073)WINGMenu.html -->
3 <html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>3 Steps to Make a WINGs User Interface</title>
4 <meta http-equiv="Content-Type" content="text/html">
5 <meta name="keywords" content="WINGs, tutorial,X11, Xlib,graphics, GUI, hack, Linux">
6 <meta name="description" content="WINGs library tutorial">
7 <meta name="license" content="GNU Free Documentation License">
9 </head>
11 <body>
12 <table align="JUSTIFY" width="100%"><tbody><tr><td align="LEFT"><a href="WINGGraphics.html">LAST: Programming Details 2</a></td><td align="CENTER"><a href="WINGtoc.html">Contents</a></td><td align="RIGHT"><a href="WINGLib.html">NEXT: Library description</a></td></tr></tbody></table>
14 <h4>Change a widget: a cascading menu</h4>
15 <p>The WINGs library offers functions to set up a structure for a menu with submenus. However, the mapping of the menu itself is left to the Window Maker window manager. Without Window Maker, a menu which has been programmed this way, will not show. The easy way around this, is to use the source code for the editable menu in the WPrefs application, change it to give it the usual menu functionality, and compile this modified source code with the application's code. The two files you need to do this, are in the Window Maker's 0.92 source code directory WPrefs.app. Copy WPrefs.app/editmenu.c and WPrefs.app/editmenu.h to your current directory. A couple of little changes to editmenu.c will be sufficient to give adequate menu/submenu functionality.
16 </p><p>Change the editable menu widget <code>struct W_EditMenuItem</code>. The EditMenuItem structure is the structure which is used to programme the editable menu in the Window Maker Preferences utility. To use it as a regular menu, it needs a pointer to the function which you want to execute when you click the item. Any WINGs widget structure needs to keep <code>W_Class widgetClass</code> and <code>WMView *view</code> as its first two declarations. Insert the line <code>WMAction * callback;</code> somewhere after them. The widget declaration will now be:
17 </p><pre><code>
18 typedef struct W_EditMenuItem {
19 W_Class widgetClass;
20 WMView *view;
22 struct W_EditMenu *parent;
23 char *label;
24 WMPixmap *pixmap;
25 void *data;
26 WMCallback *destroyData;
27 WMAction * callback;
28 struct W_EditMenu *submenu;
29 struct {
30 unsigned isTitle:1;
31 unsigned isHighlighted:1;
32 } flags;
33 } EditMenuItem;</code></pre>
34 For convenience, add this function to editmenu.c, too:
35 <pre><code>void WSetEditMenuItemAction(WEditMenuItem *item, WMAction *callback)
37 item-&gt;callback = callback;
38 }</code></pre>
40 <p><a name="overrideMenu"><img src="./WINGMenu_files/menu.jpeg" align="right"></a>We shall make a window with one button which will make the menu pop up. The code to create the menu is as follows. Have editmenu.c and editmenu.h in the same directory as the window application code, insert <code>#include "editmenu.h"</code> somewhere at the top.
41 </p><pre><code>
42 WEditMenu *submenu, *menu;
43 WEditMenuItem * menuitem;
45 submenu = WCreateEditMenu(screen, "Submenu");
46 menuitem = WAddMenuItemWithTitle(submenu, "Submenu item");
47 menu=WCreateEditMenu(screen, "Main menu");
48 menuitem = WAddMenuItemWithTitle(menu, "To submenu");
49 WSetEditMenuSubmenu(menu, menuitem, submenu);
50 menuitem = WAddMenuItemWithTitle(menu, "Main item");
51 WMRealizeWidget(submenu);
52 WMRealizeWidget(menu);</code></pre>
53 The function to map the window w's menu at point (x,y) is <code>WEditMenuShowAt(menu,x,y,w)</code>. However, it will not show anything unless it is used after the intial window has been mapped. To do this, we use <code>WMSetButtonAction</code> on a button, and make the WMAction map the menu. We pass it pointers to both the menu and the window, so that we can map the menu in the window's neighbourhood. The WMAction will look like :
54 <pre><code>void getMenu(WMWidget *self, void *data){
55 WMPoint position;
56 struct datacouple *tmp = (struct datacouple *) data;
58 if (WMGetButtonSelected(self)) {
59 position = WMGetViewScreenPosition(WMWidgetView(tmp-&gt;window));
60 WEditMenuShowAt(tmp-&gt;menu, (position.x &gt; MENUWIDTH)?position.x-MENUWIDTH:0,
61 position.y + MENITEMHT, tmp-&gt;window);
62 } else
63 WEditMenuHide(tmp-&gt;menu);
64 }</code></pre> The used structure is <code>struct datacouple{WMWindow *window; WEditMenu *menu;} datacouple;
65 </code>. Realize the window before the others. The code with details is <a href="EighthWindow.c">here</a>. To compile it, you now type <kbd>cc -x c EighthWindow.c editmenu.c -lXft -L/usr/X11/lib -L/usr/lib -lWINGs -lwraster -o EighthWindow</kbd>. editmenu.c is, of course, the modified source file.
66 <p>To use the callback functions, we need to execute them somewhere. To do this, search the <code>static void selectItem</code> function in the editmenu.c source. After its last line, <a name="talkInsertCallback">insert</a> the line: <code>if (menu-&gt;selectedItem-&gt;callback) menu-&gt;selectedItem-&gt;callback(menu-&gt;selectedItem,NULL);</code>. Define the callback before main as, eg.:
67 </p><pre><code>void menuItemAction(void *self, void *data) {
68 fprintf(stderr, "Selected\n");
69 }</code></pre>
70 and add it to the menu items in the <code>main</code> code with the <code> WSetEditMenuItemAction( menuitem, menuItemAction);</code>. There is also a little addition to the getMenu function, to reset the menu when we hide it.
72 <p>The function <code>WCreateEditMenuItem</code> in editmenu.c associates to ButtonPress events on the menu item widget, the function <code>handleItemClick</code>. This event handler function calls the function <code>selectItem</code> when it gets this event, and does a few other things we shall not need any more. The selectItem function goes through a few things. If the clicked menu item is a submenu entry, it checks its location and maps the submenu. At the end of this function we have <a href="WINGMenu.html#talkInsertCallback">inserted</a> the line which calls our callback function in case the pointer to it is not <code>NULL</code>. If the menu has to appear, legacy-style, below a fixed bar in the window's top, we would just need to calculate this position, and also need to hide the menu whenever we drag the window itself. For a free floating menu, the latter is not very important.
73 </p><p>The application source code is <a href="NinthWindow.c">here</a>. The editmenu.c code with the first few changes in it, is <a href="editmenu.c">here</a>. The changes are marked by a comment starting with <code>/* MOD </code>. There is one change in the new <a href="editmenu.h">editmenu.h</a> file.
74 </p><h5>Window manager hints</h5>
75 <p></p><table align="left" width="20%" clear="right"><tbody><tr><td><img src="./WINGMenu_files/redirectmenu1.jpeg" align="left" width="100%"></td></tr><tr><td><img src="./WINGMenu_files/redirectmenu2.jpeg" align="left" width="100%"></td></tr></tbody></table>As the menu does not have the functions of an ordinary application window, we would not want it to have the same window frame. The buttons in the titlebar may be omitted, or limited. This can be done by the window manager, on data obtained from the X server.The X server, in its turn, gets them from the application. The XLib function <code> XSetTransientForHint</code> will, in xfce4, make the menu widget look like the one in the image shown on the left. The window manager gives it a title bar and button. It also allows to drag the menu. The code must provide functions to handle the event that the close button on the title bar is clicked, or the menu window will have the same problem as our <a href="WINGStep1.html#talkMissing">first window</a>. The window manager can also be bypassed. To do this, there is the Xlib function <code> int XChangeWindowAttributes<wbr>(Display *display, Window w,
76 unsigned long valuemask, XSetWindowAttributes
77 *attributes)</code>. As shown in the example code, it can be used to set the window attribute <code>override_redirect</code>. This will block window manager interference with the placement of windows. The menu window will now in all window managers look like the one in the <a href="WINGMenu.html#overrideMenu">first image</a> at the top of this page.
78 <p align="left"><br><br>
79 <br>
80 </p><p>
81 </p><table align="JUSTIFY" width="100%"><tbody><tr><td align="LEFT"><a href="WINGGraphics.html">LAST: Programming Details 2</a></td><td align="CENTER"><a href="WINGtoc.html">Contents</a></td><td align="RIGHT"><a href="WINGLib.html">NEXT: Library description</a></td></tr></tbody></table>
84 </body><style type="text/css">embed[type*="application/x-shockwave-flash"],embed[src*=".swf"],object[type*="application/x-shockwave-flash"],object[codetype*="application/x-shockwave-flash"],object[src*=".swf"],object[codebase*="swflash.cab"],object[classid*="D27CDB6E-AE6D-11cf-96B8-444553540000"],object[classid*="d27cdb6e-ae6d-11cf-96b8-444553540000"],object[classid*="D27CDB6E-AE6D-11cf-96B8-444553540000"]{ display: none !important;}</style></html>