add mask color radio btn sel, fix del all mask btn, fix mask dflt kfrm draw name...
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcdisplayinfo.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplay.h"
23 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
25 #include "bcwindowbase.h"
26 #include "clip.h"
27 #include "language.h"
28
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <unistd.h>
33
34 #define TEST_SIZE 128
35 #define TEST_DSIZE 28
36 #define TEST_SIZE2 164
37
38 int BC_DisplayInfo::top_border = -1;
39 int BC_DisplayInfo::left_border = -1;
40 int BC_DisplayInfo::bottom_border = -1;
41 int BC_DisplayInfo::right_border = -1;
42 int BC_DisplayInfo::auto_reposition_x = -1;
43 int BC_DisplayInfo::auto_reposition_y = -1;
44
45
46 BC_DisplayInfo::BC_DisplayInfo(const char *display_name, int show_error)
47 {
48         screen = -1;
49         xinerama_screens = -1;
50         xinerama_info = 0;
51         init_window(display_name, show_error);
52 }
53
54 BC_DisplayInfo::~BC_DisplayInfo()
55 {
56         if( xinerama_info ) XFree(xinerama_info);
57 #ifndef SINGLE_THREAD
58         XCloseDisplay(display);
59 #endif
60 }
61
62
63 void BC_DisplayInfo::parse_geometry(char *geom, int *x, int *y, int *width, int *height)
64 {
65         XParseGeometry(geom, x, y, (unsigned int*)width, (unsigned int*)height);
66 }
67
68
69 int BC_DisplayInfo::get_xinerama_screens()
70 {
71         if( xinerama_screens < 0 ) {
72                 xinerama_screens = 0;
73                 if( XineramaIsActive(display) )
74                         xinerama_info = XineramaQueryScreens(display, &xinerama_screens);
75         }
76         return xinerama_screens;
77 }
78
79 int BC_DisplayInfo::xinerama_geometry(int screen, int &x, int &y, int &w, int &h)
80 {
81         int screens = get_xinerama_screens();
82         if( !screens ) return 1;
83         if( screen >= 0 ) {
84                 int k = screens;
85                 while( --k >= 0 && xinerama_info[k].screen_number != screen );
86                 if( k < 0 ) return 1;
87                 x = xinerama_info[k].x_org;  w = xinerama_info[k].width;
88                 y = xinerama_info[k].y_org;  h = xinerama_info[k].height;
89         }
90         else {
91                 int sx0 = INT_MAX, sx1 = INT_MIN;
92                 int sy0 = INT_MAX, sy1 = INT_MIN;
93                 for( int i=0; i<screens; ++i ) {
94                         int x0 = xinerama_info[i].x_org;
95                         int x1 = x0 + xinerama_info[i].width;
96                         if( sx0 > x0 ) sx0 = x0;
97                         if( sx1 < x1 ) sx1 = x1;
98                         int y0 = xinerama_info[i].y_org;
99                         int y1 = y0 + xinerama_info[i].height;
100                         if( sy0 > y0 ) sy0 = y0;
101                         if( sy1 < y1 ) sy1 = y1;
102                 }
103                 x = sx0;  w = sx1 - sx0;
104                 y = sy0;  h = sy1 - sy0;
105         }
106         return 0;
107 }
108
109 static void get_top_coords(Display *display, Window win, int &px,int &py, int &tx,int &ty)
110 {
111         Window *pcwin = 0;  unsigned int ncwin = 0;
112         Window cwin = 0, pwin = 0, root = 0;
113         XQueryTree(display, win, &root, &pwin, &pcwin, &ncwin);
114         if( pcwin ) XFree(pcwin);
115         XTranslateCoordinates(display, pwin, root, 0,0, &px,&py, &cwin);
116 //printf(" win=%lx, px/py=%d/%d\n", win, px,py);
117
118         int nx = px, ny = py;  pwin = win;
119         for( int i=5; --i>=0; ) {
120                 win = pwin;  pwin = 0;  pcwin = 0;  ncwin = 0;
121                 Window rwin = 0;
122 // XQuerytTree has been known to fail here
123                 XQueryTree(display, win, &rwin, &pwin, &pcwin, &ncwin);
124                 if( pcwin ) XFree(pcwin);
125                 if( !rwin || rwin != root || pwin == root ) break;
126                 XTranslateCoordinates(display, pwin, root, 0,0, &nx,&ny, &cwin);
127 //printf(" win=%lx, nx/ny=%d/%d\n", win, nx,ny);
128         }
129         tx = nx;  ty = ny;
130 }
131
132
133 void BC_DisplayInfo::test_window(int &x_out,
134         int &y_out,
135         int &x_out2,
136         int &y_out2,
137         int x_in,
138         int y_in)
139 {
140 #ifdef SINGLE_THREAD
141         BC_Display::lock_display("BC_DisplayInfo::test_window");
142 #endif
143
144         x_out = 0;
145         y_out = 0;
146         int x_out1 = 0;
147         int y_out1 = 0;
148         x_out2 = 0;
149         y_out2 = 0;
150
151         unsigned long mask = CWEventMask | CWWinGravity | CWBackPixel;
152         XSetWindowAttributes attr;
153         attr.event_mask = StructureNotifyMask;
154         attr.win_gravity = SouthEastGravity;
155         attr.background_pixel = BlackPixel(display,screen);
156         Window win = XCreateWindow(display, rootwin,
157                         x_in, y_in, TEST_SIZE, TEST_SIZE,
158                         0, default_depth, InputOutput,
159                         vis, mask, &attr);
160         XSizeHints size_hints;
161         XGetNormalHints(display, win, &size_hints);
162         size_hints.flags = PPosition | PSize;
163         size_hints.x = x_in;
164         size_hints.y = y_in;
165         size_hints.width = TEST_SIZE;
166         size_hints.height = TEST_SIZE;
167         XSetStandardProperties(display, win,
168                 "x", "x", None, 0, 0, &size_hints);
169         XClearWindow(display, win);
170         XMapWindow(display, win);
171         XFlush(display);  XSync(display, 0);  usleep(100000);
172
173         XEvent event;
174         int state = 0;
175
176         while( state < 3 ) {
177                 XNextEvent(display, &event);
178 //printf("BC_DisplayInfo::test_window 1 event=%d %d\n", event.type, XPending(display));
179                 if( event.xany.window != win ) continue;
180                 if( event.type != ConfigureNotify ) continue;
181                 Window cwin = 0;
182                 int rx = 0, ry = 0, px = 0, py = 0, tx = 0, ty = 0;
183 //printf("BC_DisplayInfo::test_window 1 state=%d x=%d y=%d w=%d h=%d bw=%d sev=%d\n",
184 //  state, event.xconfigure.x, event.xconfigure.y,
185 //  event.xconfigure.width, event.xconfigure.height,
186 //  event.xconfigure.border_width, event.xconfigure.send_event);
187                 get_top_coords(display,win, px,py, tx,ty);
188 //printf("x_in,y_in=%d,%d dx,dy=%d,%d\n", x_in,y_in, x_in-tx,y_in-ty);
189                 switch( state ) {
190                 case 0: // Get creation config
191                         XTranslateCoordinates(display, win, rootwin, 0,0, &rx,&ry, &cwin);
192                         x_out = rx - x_in;
193                         y_out = ry - y_in;
194                         XMoveResizeWindow(display, win, x_in,y_in, TEST_SIZE2,TEST_SIZE2);
195                         XFlush(display);  XSync(display, 0);  usleep(100000);
196                         ++state;
197                         break;
198                 case 1: // Get moveresize resizing
199                         XTranslateCoordinates(display, win, rootwin, 0,0, &rx,&ry, &cwin);
200                         x_out1 = px;
201                         y_out1 = py;
202                         x_in += TEST_DSIZE;  y_in += TEST_DSIZE;
203                         XMoveResizeWindow(display, win, x_in,y_in, TEST_SIZE2,TEST_SIZE2);
204                         XFlush(display);  XSync(display, 0);  usleep(100000);
205                         ++state;
206                         break;
207                 case 2: // Get moveresize move
208                         XTranslateCoordinates(display, win, rootwin, 0,0, &rx,&ry, &cwin);
209                         x_out2 = px - x_out1 - TEST_DSIZE;
210                         y_out2 = py - y_out1 - TEST_DSIZE;
211                         ++state;
212                         break;
213                 }
214         }
215 //printf("\nBC_DisplayInfo::test_window 3 x0,y0=%d,%d, x1,y1=%d,%d, x2,y2=%d,%d\n",
216 //  x_out,y_out, x_out1,y_out1, x_out2,y_out2);
217 //printf("\nx_in,y_in=%d,%d\n", x_in,y_in);
218
219         XDestroyWindow(display, win);
220         XFlush(display);
221         XSync(display, 0);
222
223         x_out = MAX(0, MIN(x_out, 48));
224         y_out = MAX(0, MIN(y_out, 48));
225
226 #ifdef SINGLE_THREAD
227         BC_Display::unlock_display();
228 #endif
229 }
230
231 void BC_DisplayInfo::init_borders()
232 {
233         if(top_border < 0)
234         {
235                 BC_DisplayInfo display_info;
236                 display_info.test_window(left_border, top_border,
237                         auto_reposition_x, auto_reposition_y, 100, 100);
238                 right_border = left_border;
239                 bottom_border = left_border;
240 //printf("BC_DisplayInfo::init_borders border=%d %d auto=%d %d\n",
241 //  left_border, top_border, auto_reposition_x, auto_reposition_y);
242         }
243 }
244
245
246 int BC_DisplayInfo::get_top_border()
247 {
248         init_borders();
249         return top_border;
250 }
251
252 int BC_DisplayInfo::get_left_border()
253 {
254         init_borders();
255         return left_border;
256 }
257
258 int BC_DisplayInfo::get_right_border()
259 {
260         init_borders();
261         return right_border;
262 }
263
264 int BC_DisplayInfo::get_bottom_border()
265 {
266         init_borders();
267         return bottom_border;
268 }
269
270 void BC_DisplayInfo::init_window(const char *display_name, int show_error)
271 {
272         if(display_name && display_name[0] == 0) display_name = NULL;
273
274 #ifdef SINGLE_THREAD
275         display = BC_Display::get_display(display_name);
276 #else
277
278 // This function must be the first Xlib
279 // function a multi-threaded program calls
280         XInitThreads();
281
282         if((display = XOpenDisplay(display_name)) == NULL)
283         {
284                 if(!show_error) return;
285                 fprintf(stderr,_("BC_DisplayInfo::init_window: cannot open display \"%s\".\n"),
286                         display_name ? display_name : "");
287                 if(getenv("DISPLAY") == NULL)
288                         fprintf(stderr, _("'DISPLAY' environment variable not set.\n"));
289                 if((display = XOpenDisplay(0)) == NULL) {
290                         fprintf(stderr,_("BC_DisplayInfo::init_window: cannot connect to X server.\n"));
291                         exit(1);
292                 }
293         }
294 #endif // SINGLE_THREAD
295
296 #ifdef SINGLE_THREAD
297         BC_Display::lock_display("BC_DisplayInfo::init_window");
298 #endif
299         screen = DefaultScreen(display);
300         rootwin = RootWindow(display, screen);
301         vis = DefaultVisual(display, screen);
302         default_depth = DefaultDepth(display, screen);
303 #ifdef SINGLE_THREAD
304         BC_Display::unlock_display();
305 #endif // SINGLE_THREAD
306 }
307
308
309 int BC_DisplayInfo::get_root_w()
310 {
311 #ifdef SINGLE_THREAD
312         BC_Display::lock_display("BC_DisplayInfo::get_root_w");
313 #endif
314         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
315         int result = WidthOfScreen(screen_ptr);
316 #ifdef SINGLE_THREAD
317         BC_Display::unlock_display();
318 #endif
319         return result;
320 }
321
322 int BC_DisplayInfo::get_root_h()
323 {
324 #ifdef SINGLE_THREAD
325         BC_Display::lock_display("BC_DisplayInfo::get_root_h");
326 #endif
327         Screen *screen_ptr = XDefaultScreenOfDisplay(display);
328         int result = HeightOfScreen(screen_ptr);
329 #ifdef SINGLE_THREAD
330         BC_Display::unlock_display();
331 #endif
332         return result;
333 }
334
335 int BC_DisplayInfo::get_abs_cursor_x()
336 {
337         int abs_x, abs_y, win_x, win_y;
338         unsigned int temp_mask;
339         Window temp_win;
340
341 #ifdef SINGLE_THREAD
342         BC_Display::lock_display("BC_DisplayInfo::get_abs_cursor_x");
343 #endif
344         XQueryPointer(display,
345            rootwin,
346            &temp_win,
347            &temp_win,
348        &abs_x,
349            &abs_y,
350            &win_x,
351            &win_y,
352            &temp_mask);
353 #ifdef SINGLE_THREAD
354         BC_Display::unlock_display();
355 #endif
356         return abs_x;
357 }
358
359 int BC_DisplayInfo::get_abs_cursor_y()
360 {
361         int abs_x, abs_y, win_x, win_y;
362         unsigned int temp_mask;
363         Window temp_win;
364
365 #ifdef SINGLE_THREAD
366         BC_Display::lock_display("BC_DisplayInfo::get_abs_cursor_y");
367 #endif
368         XQueryPointer(display,
369            rootwin,
370            &temp_win,
371            &temp_win,
372        &abs_x,
373            &abs_y,
374            &win_x,
375            &win_y,
376            &temp_mask);
377 #ifdef SINGLE_THREAD
378         BC_Display::unlock_display();
379 #endif
380         return abs_y;
381 }
382
383
384 int BC_DisplayInfo::get_screen_count()
385 {
386         return XScreenCount(display);
387 }
388
389
390 const char *BC_DisplayInfo::host_display_name(const char *display_name)
391 {
392         return XDisplayName(display_name);
393 }
394