Update tutorial link
[whome.git] / WINGs_tutorial / WINGsRemark.html
blobf80a0ca7a81291416ef223059db68be21cd3920f
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2 <!-- saved from url=(0075)WINGsRemark.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, Introduction, C, programming, GUI, Window Maker, 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="WINGStep3.html">LAST: Step 3 Adding Widgets</a></td><td align="CENTER"><a href="WINGtoc.html">Contents</a></td><td align="RIGHT"><a href="WINGGraphics.html">NEXT: Programming Details 2</a></td></tr></tbody></table>
14 <h4>Programming details and WINGs functions</h4>
16 <h5>Count the windows</h5>
17 In the code up till now, we had just one window. When it receives notificaton that the window is requested to close, it shuts down the whole application. In an application with more windows open, we might not like it when closing an arbitrary window shuts everything down. An obvious solution is to exit the programma when the last open window is requested to close, and keep a count of the number of windows open. The closeAll function becomes:
18 <pre><code>int windowcounter=0;
19 void closeAll(WMWidget *self,void *data){
20 WMDestroyWidget(self);
21 fprintf(stderr,"I've been used!");
22 if(--windowcounter&lt;1) exit(0);
23 }</code></pre>
24 A second window should be opened with the existing screen as an argument. After success in opening, you increase <code>windowcounter</code> by one.
25 <h5><a name="talkIcons">Icons and images</a></h5>
26 <p>Defining an icon which will be used for your application, and drawing an image in a widget, are quite straightforward. Suppose, there is an XPM-image available, and it is the file /usr/include/<wbr>pixmaps/<wbr>picture.xpm. The following code sets an application icon and draws an icon in a label.
27 </p><pre><code>RContext *ctxt;
28 RImage *img;
29 WMPixmap *wimg;
30 /* code to open screen, window*/
31 ctxt=WMScreenRContext(screen);
32 img=RLoadXPM(ctxt, "/usr/include/pixmaps/picture.xpm", 0);
33 WMSetApplicationIconImage(screen, img);
34 wimg= WMCreatePixmapFromRImage(screen, img,0);
35 /* code to create a label */
36 WMSetLabelImagePosition(label, WIPImageOnly);
37 WMSetLabelImage(label, wimg);</code></pre>
38 <code>RContext</code> refers to the X-server's so-called <a name="talkGraphicsContext">graphics context</a>. This specifies which line width, fill patterns, etc. will be used. That information is not contained in the XPM-file. With <code>WMScreenRContext</code>, we use the existing context. <code>RLoadXPM</code> loads the xpm from a file, and stores it as an RImage.
39 <p> The image is set as an icon for the application with this RImage. We transform the RImage into a WMPixmap. The WMPixmap can be shown in a widget. Here, we show it in a label with <code>WMSetLabelImage </code>. You must specify its position with the right <a href="WINGLib.html#ImagePositions">option</a> first.
40 </p><p>An X pixmap is a text file. You can insert its code into your application source code directly, and handle it with <code>RGetImageFromXPMData</code>
42 </p><h5><a name="talkResolution">Virtual screen and resolution</a></h5>
44 <p>
45 WINGs provide the function <code> unsigned int WMScreenWidth (WMScreen *wmscr)</code> to get the screen's width in pixels. There is a similar function to get its height. This is information about the virtual screen, and is not always what you are looking for. Many (or all?) Gtk+ interfaces have bigger font sizes when the virtual screen is bigger, even when the monitor is the same. If your monitor runs at 1024x768, and your virtual screen measures 1800x1440 pixels, you would often want to adjust your application to the monitor's resolution, and the view it has on the virtual screen, rather than to the screen's size itself. To get the used video mode (ie. the 1024x768 in our example), and the position on the virtual screen, the X-library libXxf86vmode provides two functions.
46 </p><ul>
47 <li><code> Bool XF86VidModeGetModeLine( Display *display, int screen, int *dotclock_return, XF86VidModeModeLine *modeline)</code>
48 </li><li><code> Bool XF86VidModeGetViewPort( Display *display, int screen, int *x_return, int *y_return)</code>
49 </li></ul>
50 The returned <code>modeline</code> is a structure which has members <code>hdisplay</code> and <code>vdisplay</code>. The monitor's current resolution is <code>hdisplay x vdisplay</code>. The monitor's left uppper corner is at the position returned by <code>XF86VidModeGetViewPort</code> in <code>*x_return x *y-return</code>. The <code>screen</code> parameter in these function calls is <em>not</em> a WMScreen variable. A WMScreen variable <code>wmscr</code>is a structure, defined in WINGsP.h, which contains the screen number in a member <code>wmscr.screen</code>. The follwing example defines a function <code>*WMGetModeViewSSize()</code> For simplicity, it is assumed the application is using the default screen. The argument to the <code>WMScreenWidth</code> function should of course be a WMScreen type.
52 <pre><code> /* extra headers */
53 #include &lt;X11/Xlib.h&gt;
54 #include &lt;X11/extensions/xf86vmode.h&gt;
56 Display *display;
57 WMScreen *screen;
59 int *WMGetModeViewSSize(){
60 int *result;
61 XF86VidModeModeLine modeline;
62 int dotclock_return;
64 result=(int *)calloc(8,sizeof(int));
66 XF86VidModeGetModeLine(display,DefaultScreen(display), &amp;dotclock_return,&amp;modeline);
67 *result= modeline.hdisplay;
68 result[1]= modeline.vdisplay;
69 XF86VidModeGetViewPort(display,DefaultScreen(display), result+2,result+3);
70 result[4]=WMScreenWidth(screen);
71 result[5]=WMScreenHeight(screen);
73 return result;
74 }</code></pre>
75 <img src="./WINGsRemark_files/ScreenSize.jpeg" align="right" width="50%">To compile this function, you need the <kbd>libXxf86vm</kbd> library. For the GNU compiler, your command would now be <kbd>gcc -x c -lXft FileName.c -L/usr/X11/lib -L/usr/lib -lWINGs -lwraster -lXxf86vm -o FileName</kbd>. When you run the function (after opening the screen), and print its results, you will find something like: <pre><code>result 0 and 1: 1024 768
76 result 2 and 3: 126 171
77 result 4 and 5: 1800 1440</code></pre>
78 meaning that the monitor is running at 1024x768, its upper left corner is at (126,171) in the virtual screen, and the whole screen has a resolution of 1800x1440. The user is seeing the screen part from (126,171) to (1150,939). In the illustration to the right, (X,Y) represent the Viewport coordinates which are obtained from <code>XF86VidModeGetViewPort</code>. The bright part is the part of the virtual screen which is visible on the monitor at that moment.
80 <h5><a name="talkMessageLog">Message log window</a></h5>
81 <p>In all the applications up till now, error and other messages have been sent to stderr or stdout. when you start the programmes by (double-)clicking in your file manager, the messages may disappear, or pop up in a window. This makes starting the application from an xterm command line the most practical. To get rid of this disappointing feature, you can programme another window to send the messages to, or, more logically, use a named pipe to send them to a different application which you already have on your system. This section gives an example how to code this last method.
82 </p><p>The method is simple: when the first message needs to be written, the code creates the pipe with <code>mknod</code>. If successful, it forks. The child process uses unix' <code>execlp</code> to start the logging application. In this example it is <kbd>xconsole</kbd>, with the pipe as its file argument. The parent process opens the pipe for writing. The application now can write to the pipe.
83 </p><p>The first detail is in the function to close our applicaton, <code>closeAll</code>, in the examples. This function should terminate the child process, and also delete the file which was used for piping the data. The second detail is the way we keep track if the child process is still running, or whether the user has clicked it away. For this we declare a signal handler each time we start up the child process. At the SIGCHLD signal, which indicates the child process has been terminated, we call a function which deletes the pipe file as well, and sets a global variable to a value which allows us to check if the child process has terminated. When writing our second message, we check first if the child process is still running. If it is, we can write to the pipe, if it isn't, we create a new child process and pipe. If there is any problem, we fall back on the usual stderr. Here is the (extra) code for a simple implementation:
85 </p><pre><code>#include &lt;fcntl.h&gt;
86 #include &lt;signal.h&gt;
87 #include &lt;sys/stat.h&gt;
88 #define ERRMSGFIFO "/tmp/WINGsWindowfifo"
89 #define NOLOGWINDOW (-2)
90 #define FIFOERROR (-1)
91 #define FIFOLOWESTPOSS 0
93 int fifonr=NOLOGWINDOW; /* the fifo nr, or an error value */
94 int sibpid; /* the child's process ID */
97 /* clean up when closing: */
99 void closeAll(WMWidget *self,void *data){
101 WMDestroyWidget(self);
102 if(--windowCounter&lt;1){
103 if (fifonr&gt;=FIFOLOWESTPOSS)
104 kill(sibpid,SIGTERM);
105 if (!access(ERRMSGFIFO,F_OK|W_OK))
106 unlink(ERRMSGFIFO);
107 exit(0);
111 /* handle the case the child terminates. Set fifonr and clean up: */
113 void redirectmsg(int sig){
115 fifonr=NOLOGWINDOW;
116 if (!access(ERRMSGFIFO,F_OK|W_OK))
117 unlink(ERRMSGFIFO);
118 return;
122 /* have the log window pop up: */
124 int showMessageWindow(){
126 (void) signal(SIGCHLD,redirectmsg); /* use redirectmsg whenever the child process stops */
128 if(access(ERRMSGFIFO,F_OK)==-1)
129 fifonr=mknod(ERRMSGFIFO,0640|O_EXCL|S_IFIFO,(dev_t)0);
130 else
131 fifonr=FIFOERROR;
132 /* fifonr == FIFOERROR if mkfifo or access failed, for mknod returns -1 on failure */
134 if(fifonr!=FIFOERROR){
136 sibpid=fork();
138 if(sibpid==0){
139 execlp("xconsole" , "xconsole", "-file",ERRMSGFIFO,"-geometry","250x400", \
140 "-title","Application Messages",(char *)0);
141 exit(1);
143 else
144 fifonr=open(ERRMSGFIFO,O_WRONLY);
146 return fifonr;
150 /* usage: */
152 void someActionWithMessage(void *self, void *data){
154 if (fifonr&lt;FIFOLOWESTPOSS)
155 fifonr=showMessageWindow(); /* (re)start xconsole, or try again in case of FIFOERROR */
157 if (fifonr==FIFOERROR) /* if still error, use stderr */
158 fprintf(stderr,"%s selected\n", WMgetSomeInformationFrom(self));
159 else{
160 char textbuffer[100];
161 snprintf(textbuffer,99, "%s is the information\n", WMGetSomeInformationFrom(self));
162 write(fifonr, textbuffer,strlen(textbuffer));
165 </code></pre>
167 The <code>someActionWithMessage</code> function is a <a href="WINGStep2.html#WMAction">WMAction</a> in this case. Of course, there must be an xconsole in the user's path and he needs the correct rights. The example catches the events that the user clicks away the xconsole before he is finished, that the fifo file already exists, and that the fifo file is replaced with something which is not accessible during run time. There is nothing to change in <code>main</code>.
169 <br>
170 </p><p>
171 </p><table align="JUSTIFY" width="100%"><tbody><tr><td align="LEFT"><a href="WINGStep3.html">LAST: Step 3 Adding Widgets</a></td><td align="CENTER"><a href="WINGtoc.html">Contents</a></td><td align="RIGHT"><a href="WINGGraphics.html">NEXT: Programming Details 2</a></td></tr></tbody></table>
174 </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>