1 /*
2  * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Kevin E. Martin <kem@redhat.com>
31  *   David H. Dawes <dawes@xfree86.org>
32  *
33  */
34 
35 /** \file
36  * This file provides support for screen initialization. */
37 
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
40 #endif
41 
42 #include "dmx.h"
43 #include "dmxsync.h"
44 #include "dmxscrinit.h"
45 #include "dmxcursor.h"
46 #include "dmxgc.h"
47 #include "dmxgcops.h"
48 #include "dmxwindow.h"
49 #include "dmxpixmap.h"
50 #include "dmxfont.h"
51 #include "dmxcmap.h"
52 #include "dmxprop.h"
53 #include "dmxdpms.h"
54 
55 #include "dmxpict.h"
56 
57 #include "fb.h"
58 #include "mipointer.h"
59 #include "micmap.h"
60 
61 #include <X11/fonts/libxfont2.h>
62 
63 extern Bool dmxCloseScreen(ScreenPtr pScreen);
64 static Bool dmxSaveScreen(ScreenPtr pScreen, int what);
65 
66 static unsigned long dmxGeneration;
67 static unsigned long *dmxCursorGeneration;
68 
69 DevPrivateKeyRec dmxGCPrivateKeyRec;
70 DevPrivateKeyRec dmxWinPrivateKeyRec;
71 DevPrivateKeyRec dmxPixPrivateKeyRec;
72 int dmxFontPrivateIndex;        /**< Private index for Fonts     */
73 DevPrivateKeyRec dmxScreenPrivateKeyRec;
74 DevPrivateKeyRec dmxColormapPrivateKeyRec;
75 DevPrivateKeyRec dmxPictPrivateKeyRec;
76 DevPrivateKeyRec dmxGlyphSetPrivateKeyRec;
77 
78 #ifdef DPMSExtension
79 static void
dmxDPMS(ScreenPtr pScreen,int level)80 dmxDPMS(ScreenPtr pScreen, int level)
81 {
82     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
83     dmxDPMSBackend(dmxScreen, level);
84 }
85 #else
86 #define dmxDPMS NULL
87 #endif
88 
89 /** Initialize the parts of screen \a idx that require access to the
90  *  back-end server. */
91 void
dmxBEScreenInit(ScreenPtr pScreen)92 dmxBEScreenInit(ScreenPtr pScreen)
93 {
94     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
95     XSetWindowAttributes attribs;
96     unsigned long mask;
97     int i, j;
98 
99     /* FIXME: The dmxScreenInit() code currently assumes that it will
100      * not be called if the Xdmx server is started with this screen
101      * detached -- i.e., it assumes that dmxScreen->beDisplay is always
102      * valid.  This is not necessarily a valid assumption when full
103      * addition/removal of screens is implemented, but when this code is
104      * broken out for screen reattachment, then we will reevaluate this
105      * assumption.
106      */
107 
108     pScreen->mmWidth = DisplayWidthMM(dmxScreen->beDisplay,
109                                       DefaultScreen(dmxScreen->beDisplay));
110     pScreen->mmHeight = DisplayHeightMM(dmxScreen->beDisplay,
111                                         DefaultScreen(dmxScreen->beDisplay));
112 
113     pScreen->whitePixel = dmxScreen->beWhitePixel;
114     pScreen->blackPixel = dmxScreen->beBlackPixel;
115 
116     /* Handle screen savers and DPMS on the backend */
117     if (dmxDPMSInit(dmxScreen))
118         pScreen->DPMS = dmxDPMS;
119 
120     /* Create root window for screen */
121     mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect;
122     attribs.background_pixel = dmxScreen->beBlackPixel;
123     attribs.event_mask = (KeyPressMask
124                           | KeyReleaseMask
125                           | ButtonPressMask
126                           | ButtonReleaseMask
127                           | EnterWindowMask
128                           | LeaveWindowMask
129                           | PointerMotionMask
130                           | KeymapStateMask | FocusChangeMask);
131     attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex];
132     attribs.override_redirect = True;
133 
134     dmxScreen->scrnWin =
135         XCreateWindow(dmxScreen->beDisplay,
136                       DefaultRootWindow(dmxScreen->beDisplay),
137                       dmxScreen->scrnX,
138                       dmxScreen->scrnY,
139                       dmxScreen->scrnWidth,
140                       dmxScreen->scrnHeight,
141                       0,
142                       pScreen->rootDepth,
143                       InputOutput,
144                       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
145                       mask, &attribs);
146     dmxPropertyWindow(dmxScreen);
147 
148     /*
149      * This turns off the cursor by defining a cursor with no visible
150      * components.
151      */
152     {
153         char noCursorData[] = { 0, 0, 0, 0,
154             0, 0, 0, 0
155         };
156         Pixmap pixmap;
157         XColor color, tmp;
158 
159         pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin,
160                                        noCursorData, 8, 8);
161         XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0],
162                          "black", &color, &tmp);
163         dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay,
164                                                   pixmap, pixmap,
165                                                   &color, &color, 0, 0);
166         XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
167                       dmxScreen->noCursor);
168 
169         XFreePixmap(dmxScreen->beDisplay, pixmap);
170     }
171 
172     XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
173 
174     /* Create default drawables (used during GC creation) */
175     for (i = 0; i < dmxScreen->beNumPixmapFormats; i++)
176 	for (j = 0; j < dmxScreen->beNumDepths; j++)
177 	    if ((dmxScreen->bePixmapFormats[i].depth == 1) ||
178 		(dmxScreen->bePixmapFormats[i].depth ==
179 		 dmxScreen->beDepths[j])) {
180 		dmxScreen->scrnDefDrawables[i] = (Drawable)
181 		    XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
182 				  1, 1,
183 				  dmxScreen->bePixmapFormats[i].depth);
184 		break;
185 	    }
186 }
187 
188 /** Initialize screen number \a pScreen->myNum. */
189 Bool
dmxScreenInit(ScreenPtr pScreen,int argc,char * argv[])190 dmxScreenInit(ScreenPtr pScreen, int argc, char *argv[])
191 {
192     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
193     int i, j;
194 
195     if (!dixRegisterPrivateKey(&dmxScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
196         return FALSE;
197     if (!dixRegisterPrivateKey(&dmxColormapPrivateKeyRec, PRIVATE_COLORMAP, 0))
198         return FALSE;
199     if (!dixRegisterPrivateKey(&dmxGlyphSetPrivateKeyRec, PRIVATE_GLYPHSET, 0))
200         return FALSE;
201 
202     if (dmxGeneration != serverGeneration) {
203         /* Allocate font private index */
204         dmxFontPrivateIndex = xfont2_allocate_font_private_index();
205         if (dmxFontPrivateIndex == -1)
206             return FALSE;
207 
208         dmxGeneration = serverGeneration;
209     }
210 
211     if (!dmxInitGC(pScreen))
212 	return FALSE;
213     if (!dmxInitWindow(pScreen))
214 	return FALSE;
215     if (!dmxInitPixmap(pScreen))
216 	return FALSE;
217 
218     /*
219      * Initalise the visual types.  miSetVisualTypesAndMasks() requires
220      * that all of the types for each depth be collected together.  It's
221      * intended for slightly different usage to what we would like here.
222      * Maybe a miAddVisualTypeAndMask() function will be added to make
223      * things easier here.
224      */
225     for (i = 0; i < dmxScreen->beNumDepths; i++) {
226         int depth;
227         int visuals = 0;
228         int bitsPerRgb = 0;
229         int preferredClass = -1;
230         Pixel redMask = 0;
231         Pixel greenMask = 0;
232         Pixel blueMask = 0;
233 
234         depth = dmxScreen->beDepths[i];
235         for (j = 0; j < dmxScreen->beNumVisuals; j++) {
236             XVisualInfo *vi;
237 
238             vi = &dmxScreen->beVisuals[j];
239             if (vi->depth == depth) {
240                 /* Assume the masks are all the same. */
241                 visuals |= (1 << vi->class);
242                 bitsPerRgb = vi->bits_per_rgb;
243                 redMask = vi->red_mask;
244                 greenMask = vi->green_mask;
245                 blueMask = vi->blue_mask;
246                 if (j == dmxScreen->beDefVisualIndex) {
247                     preferredClass = vi->class;
248                 }
249             }
250         }
251         miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass,
252                                  redMask, greenMask, blueMask);
253     }
254 
255     fbScreenInit(pScreen,
256                  NULL,
257                  dmxScreen->scrnWidth,
258                  dmxScreen->scrnHeight,
259                  dmxScreen->beXDPI,
260                  dmxScreen->beXDPI, dmxScreen->scrnWidth, dmxScreen->beBPP);
261     (void) dmxPictureInit(pScreen, 0, 0);
262 
263     /* Not yet... */
264     pScreen->GetWindowPixmap = NULL;
265     pScreen->SetWindowPixmap = NULL;
266 
267     MAXSCREENSALLOC(dmxCursorGeneration);
268     if (dmxCursorGeneration[pScreen->myNum] != serverGeneration) {
269 	if (!(miPointerInitialize(pScreen,
270 				  &dmxPointerSpriteFuncs,
271 				  &dmxPointerCursorFuncs, FALSE)))
272 	    return FALSE;
273 
274 	dmxCursorGeneration[pScreen->myNum] = serverGeneration;
275     }
276 
277     DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen);
278     DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen);
279 
280     dmxBEScreenInit(pScreen);
281 
282     /* Wrap GC functions */
283     DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen);
284 
285     /* Wrap Window functions */
286     DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen);
287     DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen);
288     DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen);
289     DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen,
290 	     pScreen);
291     DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen);
292     DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen);
293     DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen);
294     DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen);
295     DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen);
296 
297     DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen);
298     DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen);
299 
300     DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen);
301 
302     /* Wrap Image functions */
303     DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen);
304     DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen);
305 
306     /* Wrap Pixmap functions */
307     DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen);
308     DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen);
309     DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen);
310 
311     /* Wrap Font functions */
312     DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen);
313     DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen);
314 
315     /* Wrap Colormap functions */
316     DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen);
317     DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen);
318     DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen);
319     DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen);
320 
321     /* Wrap Shape functions */
322     DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen);
323 
324     if (!dmxCreateDefColormap(pScreen))
325         return FALSE;
326 
327     return TRUE;
328 }
329 
330 /** Close the \a pScreen resources on the back-end server. */
331 void
dmxBECloseScreen(ScreenPtr pScreen)332 dmxBECloseScreen(ScreenPtr pScreen)
333 {
334     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
335     int i;
336 
337     /* Restore the back-end screen-saver and DPMS state. */
338     dmxDPMSTerm(dmxScreen);
339 
340     /* Free the screen resources */
341 
342     XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor);
343     dmxScreen->noCursor = (Cursor) 0;
344 
345     XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
346     XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
347     dmxScreen->scrnWin = (Window) 0;
348 
349     /* Free the default drawables */
350     for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
351 	if (dmxScreen->scrnDefDrawables[i]) {
352 	    XFreePixmap(dmxScreen->beDisplay,
353 			dmxScreen->scrnDefDrawables[i]);
354 	    dmxScreen->scrnDefDrawables[i] = (Drawable) 0;
355 	}
356     }
357 
358     /* Free resources allocated during initialization (in dmxinit.c) */
359     for (i = 0; i < dmxScreen->beNumDefColormaps; i++)
360         XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]);
361     free(dmxScreen->beDefColormaps);
362     dmxScreen->beDefColormaps = NULL;
363 
364 #if 0
365     /* Do not free visuals, depths and pixmap formats here.  Free them
366      * in dmxCloseScreen() instead -- see comment below. */
367     XFree(dmxScreen->beVisuals);
368     dmxScreen->beVisuals = NULL;
369 
370     XFree(dmxScreen->beDepths);
371     dmxScreen->beDepths = NULL;
372 
373     XFree(dmxScreen->bePixmapFormats);
374     dmxScreen->bePixmapFormats = NULL;
375 #endif
376 
377 #ifdef GLXEXT
378     if (dmxScreen->glxVisuals) {
379         XFree(dmxScreen->glxVisuals);
380         dmxScreen->glxVisuals = NULL;
381         dmxScreen->numGlxVisuals = 0;
382     }
383 #endif
384 
385     /* Close display */
386     XCloseDisplay(dmxScreen->beDisplay);
387     dmxScreen->beDisplay = NULL;
388 }
389 
390 /** Close screen number \a idx. */
391 Bool
dmxCloseScreen(ScreenPtr pScreen)392 dmxCloseScreen(ScreenPtr pScreen)
393 {
394     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
395 
396     /* Reset the proc vectors */
397     if (pScreen->myNum == 0) {
398         dmxResetRender();
399         dmxResetFonts();
400     }
401 
402     /* Unwrap Shape functions */
403     DMX_UNWRAP(SetShape, dmxScreen, pScreen);
404 
405     /* Unwrap the pScreen functions */
406     DMX_UNWRAP(CreateGC, dmxScreen, pScreen);
407 
408     DMX_UNWRAP(CreateWindow, dmxScreen, pScreen);
409     DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen);
410     DMX_UNWRAP(PositionWindow, dmxScreen, pScreen);
411     DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen);
412     DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen);
413     DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen);
414     DMX_UNWRAP(RestackWindow, dmxScreen, pScreen);
415     DMX_UNWRAP(WindowExposures, dmxScreen, pScreen);
416     DMX_UNWRAP(CopyWindow, dmxScreen, pScreen);
417 
418     DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen);
419     DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen);
420 
421     DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen);
422 
423     DMX_UNWRAP(GetImage, dmxScreen, pScreen);
424     DMX_UNWRAP(GetSpans, dmxScreen, pScreen);
425 
426     DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen);
427     DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen);
428     DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen);
429 
430     DMX_UNWRAP(RealizeFont, dmxScreen, pScreen);
431     DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen);
432 
433     DMX_UNWRAP(CreateColormap, dmxScreen, pScreen);
434     DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen);
435     DMX_UNWRAP(InstallColormap, dmxScreen, pScreen);
436     DMX_UNWRAP(StoreColors, dmxScreen, pScreen);
437 
438     DMX_UNWRAP(SaveScreen, dmxScreen, pScreen);
439 
440     if (dmxScreen->beDisplay) {
441         dmxBECloseScreen(pScreen);
442 
443 #if 1
444         /* Free visuals, depths and pixmap formats here so that they
445          * won't be freed when a screen is detached, thereby allowing
446          * the screen to be reattached to be compared to the one
447          * previously removed.
448          */
449         XFree(dmxScreen->beVisuals);
450         dmxScreen->beVisuals = NULL;
451 
452         XFree(dmxScreen->beDepths);
453         dmxScreen->beDepths = NULL;
454 
455         XFree(dmxScreen->bePixmapFormats);
456         dmxScreen->bePixmapFormats = NULL;
457 #endif
458     }
459 
460     DMX_UNWRAP(CloseScreen, dmxScreen, pScreen);
461     return pScreen->CloseScreen(pScreen);
462 }
463 
464 static Bool
dmxSaveScreen(ScreenPtr pScreen,int what)465 dmxSaveScreen(ScreenPtr pScreen, int what)
466 {
467     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
468 
469     if (dmxScreen->beDisplay) {
470         switch (what) {
471         case SCREEN_SAVER_OFF:
472         case SCREEN_SAVER_FORCER:
473             XResetScreenSaver(dmxScreen->beDisplay);
474             dmxSync(dmxScreen, FALSE);
475             break;
476         case SCREEN_SAVER_ON:
477         case SCREEN_SAVER_CYCLE:
478             XActivateScreenSaver(dmxScreen->beDisplay);
479             dmxSync(dmxScreen, FALSE);
480             break;
481         }
482     }
483 
484     return TRUE;
485 }
486