comparison gui/wm/ws.c @ 35672:144d3a71db7d

Cosmetic: Relocate some functions. This groups functions that belong together.
author ib
date Thu, 17 Jan 2013 16:49:26 +0000
parents 8ce9bc8aa443
children 2b7f93ef711d
comparison
equal deleted inserted replaced
35671:96adc233474d 35672:144d3a71db7d
127 #define MWM_FUNC_MAXIMIZE (1L << 4) 127 #define MWM_FUNC_MAXIMIZE (1L << 4)
128 #define MWM_FUNC_CLOSE (1L << 5) 128 #define MWM_FUNC_CLOSE (1L << 5)
129 129
130 #define MWM_DECOR_ALL (1L << 0) 130 #define MWM_DECOR_ALL (1L << 0)
131 131
132 // ----------------------------------------------------------------------------------------------
133 // Init X Window System.
134 // ----------------------------------------------------------------------------------------------
135
136 /**
137 * @brief Inform about an X error that has occurred.
138 *
139 * @param display display
140 * @param event pointer to an X error event structure
141 *
142 * @return 0
143 */
144 static int wsErrorHandler(Display *display, XErrorEvent *event)
145 {
146 char type[128];
147
148 XGetErrorText(display, event->error_code, type, sizeof(type));
149
150 mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] " MSGTR_WS_XError);
151 mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] Error code: %d - %s\n", event->error_code, type);
152 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Request code: %d (minor code: %d)\n", event->request_code, event->minor_code);
153 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] MPlayer module: %s\n", current_module ? current_module : "(none)");
154
155 return 0;
156 }
157
158 /** 132 /**
159 * @brief Update screen width, screen height and screen origin x and y 133 * @brief Update screen width, screen height and screen origin x and y
160 * from xinerama information. 134 * from xinerama information.
161 * 135 *
162 * Set wsOrgX, wsOrgY, wsMaxX and wsMaxY as well as 136 * Set wsOrgX, wsOrgY, wsMaxX and wsMaxY as well as
187 win->X = wsOrgX; 161 win->X = wsOrgX;
188 win->Y = wsOrgY; 162 win->Y = wsOrgY;
189 win->Width = wsMaxX; 163 win->Width = wsMaxX;
190 win->Height = wsMaxY; 164 win->Height = wsMaxY;
191 } 165 }
192 }
193
194 /**
195 * @brief Set the X error handler.
196 */
197 void wsSetErrorHandler(void)
198 {
199 XSetErrorHandler(wsErrorHandler);
200 }
201
202 void wsXInit(Display *display)
203 {
204 int eventbase;
205 int errorbase;
206
207 mp_msg(MSGT_GPLAYER, MSGL_V, "X init.\n");
208
209 wsDisplay = display;
210
211 wsSetErrorHandler();
212
213 /* enable DND atoms */
214 wsXDNDInitialize();
215
216 { /* on remote display XShm will be disabled - LGB */
217 char *dispname = DisplayString(wsDisplay);
218 int localdisp = 1;
219
220 if (dispname && *dispname != ':') {
221 localdisp = 0;
222 wsUseXShm = False;
223 }
224
225 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] display name: %s => %s display.\n", dispname, localdisp ? "local" : "REMOTE");
226
227 if (!localdisp)
228 mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_RemoteDisplay);
229 }
230
231 #ifdef HAVE_SHM
232 if (!XShmQueryExtension(wsDisplay))
233 #endif
234 wsUseXShm = False;
235
236 if (!wsUseXShm)
237 mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_NoXshm);
238
239 #ifdef CONFIG_XSHAPE
240 if (!XShapeQueryExtension(wsDisplay, &eventbase, &errorbase))
241 #endif
242 wsUseXShape = False;
243
244 if (!wsUseXShape)
245 mp_msg(MSGT_GPLAYER, MSGL_WARN, MSGTR_WS_NoXshape);
246
247 XSynchronize(wsDisplay, True);
248
249 wsScreen = DefaultScreen(wsDisplay);
250 wsRootWin = RootWindow(wsDisplay, wsScreen);
251 #ifdef CONFIG_XF86VM
252 {
253 int clock;
254 XF86VidModeModeLine modeline;
255
256 XF86VidModeGetModeLine(wsDisplay, wsScreen, &clock, &modeline);
257 wsMaxX = modeline.hdisplay;
258 wsMaxY = modeline.vdisplay;
259 }
260 #endif
261 {
262 wsOrgX = wsOrgY = 0;
263
264 if (!wsMaxX)
265 wsMaxX = DisplayWidth(wsDisplay, wsScreen);
266
267 if (!wsMaxY)
268 wsMaxY = DisplayHeight(wsDisplay, wsScreen);
269 }
270
271 wsUpdateXineramaInfo(NULL);
272
273 wsGetDepthOnScreen();
274
275 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Screen depth: %d\n", wsDepthOnScreen);
276 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] size: %dx%d\n", wsMaxX, wsMaxY);
277
278 #ifdef CONFIG_XINERAMA
279 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] origin: +%d+%d\n", wsOrgX, wsOrgY);
280 #endif
281
282 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] red mask: 0x%x\n", wsRedMask);
283 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] green mask: 0x%x\n", wsGreenMask);
284 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] blue mask: 0x%x\n", wsBlueMask);
285
286 #ifdef HAVE_SHM
287 if (wsUseXShm) {
288 int minor, major, shp;
289
290 XShmQueryVersion(wsDisplay, &major, &minor, &shp);
291 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShm version is %d.%d\n", major, minor);
292 }
293 #endif
294
295 #ifdef CONFIG_XSHAPE
296 if (wsUseXShape) {
297 int minor, major;
298
299 XShapeQueryVersion(wsDisplay, &major, &minor);
300 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShape version is %d.%d\n", major, minor);
301 }
302 #endif
303
304 wsOutMask = wsGetOutMask();
305
306 switch (wsOutMask) {
307 case wsRGB32:
308 out_pix_fmt = PIX_FMT_RGB32;
309 break;
310
311 case wsBGR32:
312 out_pix_fmt = PIX_FMT_BGR32;
313 break;
314
315 case wsRGB24:
316 out_pix_fmt = PIX_FMT_RGB24;
317 break;
318
319 case wsBGR24:
320 out_pix_fmt = PIX_FMT_BGR24;
321 break;
322
323 case wsRGB16:
324 out_pix_fmt = PIX_FMT_RGB565;
325 break;
326
327 case wsBGR16:
328 out_pix_fmt = PIX_FMT_BGR565;
329 break;
330
331 case wsRGB15:
332 out_pix_fmt = PIX_FMT_RGB555;
333 break;
334
335 case wsBGR15:
336 out_pix_fmt = PIX_FMT_BGR555;
337 break;
338 }
339 }
340
341 /**
342 * @brief Calculate and store the x and y position for a window.
343 *
344 * @param win pointer to a ws window structure
345 * @param x x position of the window (real/absolute or mock)
346 * @param y y position of the window (real/absolute or mock)
347 * @param width width of the area to place the window in
348 * @param height height of the area to place the window in
349 */
350 static void wsWindowPosition(wsWindow *win, int x, int y, int width, int height)
351 {
352 switch (x) {
353 case -1:
354 win->X = wsOrgX + (wsMaxX - width) / 2;
355 break;
356
357 case -2:
358 win->X = wsOrgX + wsMaxX - width;
359 break;
360
361 default:
362 win->X = x;
363 break;
364 }
365
366 switch (y) {
367 case -1:
368 win->Y = wsOrgY + (wsMaxY - height) / 2;
369 break;
370
371 case -2:
372 win->Y = wsOrgY + wsMaxY - height;
373 break;
374
375 default:
376 win->Y = y;
377 break;
378 }
379 }
380
381 /**
382 * @brief Replace the size hints for the WM_NORMAL_HINTS property of a window.
383 *
384 * @param win pointer to a ws window structure
385 */
386 static void wsSizeHint(wsWindow *win)
387 {
388 XSizeHints size;
389
390 size.flags = 0;
391
392 /* obsolete, solely for compatibility reasons */
393 size.flags |= PPosition;
394 size.x = win->X;
395 size.y = win->Y;
396
397 /* obsolete, solely for compatibility reasons */
398 size.flags |= PSize;
399 size.width = win->Width;
400 size.height = win->Height;
401
402 /* a minimum of 4 is said to avoid off-by-one errors and be required by mga_vid */
403 size.flags |= PMinSize;
404 size.min_width = 4;
405 size.min_height = 4;
406
407 if (win->Property & wsMinSize) {
408 size.min_width = win->Width;
409 size.min_height = win->Height;
410 }
411
412 if (win->Property & wsMaxSize) {
413 size.flags |= PMaxSize;
414 size.max_width = win->Width;
415 size.max_height = win->Height;
416 }
417
418 if (vo_keepaspect && (win->Property & wsAspect)) {
419 size.flags |= PAspect;
420 size.min_aspect.x = win->Width;
421 size.min_aspect.y = win->Height;
422 size.max_aspect.x = win->Width;
423 size.max_aspect.y = win->Height;
424 }
425
426 size.flags |= PBaseSize;
427 size.base_width = 0;
428 size.base_height = 0;
429
430 size.flags |= PWinGravity;
431 size.win_gravity = StaticGravity;
432
433 XSetWMNormalHints(wsDisplay, win->WindowID, &size);
434 }
435
436 /**
437 * @brief Wait until a window is mapped if its property requires it.
438 *
439 * @param win pointer to a ws window structure
440 */
441 static void wsMapWait(wsWindow *win)
442 {
443 XEvent xev;
444
445 if (win->Property & wsWaitMap) {
446 do
447 XNextEvent(wsDisplay, &xev);
448 while (xev.type != MapNotify || xev.xmap.event != win->WindowID);
449
450 win->Mapped = wsMapped;
451 }
452 }
453
454 // ----------------------------------------------------------------------------------------------
455 // Create window.
456 // X,Y : window position
457 // wX,wY : size of window
458 // bW : border width
459 // cV : visible mouse cursor on window
460 // D : visible frame, title, etc.
461 // sR : screen ratio
462 // ----------------------------------------------------------------------------------------------
463
464 XClassHint wsClassHint;
465 XTextProperty wsTextProperty;
466 Window LeaderWindow;
467
468 // ----------------------------------------------------------------------------------------------
469 // wsCreateWindow: create a new window on the screen.
470 // x,y : window position
471 // w,h : window size
472 // b : window border size
473 // c : mouse cursor visible
474 // p : properties - "decoration", visible titlebar, etc ...
475 // ----------------------------------------------------------------------------------------------
476 void wsCreateWindow(wsWindow *win, int x, int y, int w, int h, int b, int c, unsigned char p, char *label)
477 {
478 int depth;
479
480 win->Property = p;
481
482 if (p & wsShowFrame)
483 win->Decorations = True;
484
485 wsWindowPosition(win, x, y, w, h);
486
487 win->Width = w;
488 win->Height = h;
489 win->OldX = win->X;
490 win->OldY = win->Y;
491 win->OldWidth = win->Width;
492 win->OldHeight = win->Height;
493
494 /* Border size for window. */
495 win->BorderWidth = b;
496 /* Hide Mouse Cursor */
497 win->wsCursor = None;
498 win->wsMouseEventType = c;
499 win->wsCursorData[0] = 0;
500 win->wsCursorPixmap = XCreateBitmapFromData(wsDisplay, wsRootWin, win->wsCursorData, 1, 1);
501
502 if (!(c & wsShowMouseCursor))
503 win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0);
504
505 depth = vo_find_depth_from_visuals(wsDisplay, wsScreen, NULL);
506
507 if (depth < 15) {
508 mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ColorDepthTooLow);
509 mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
510 }
511
512 XMatchVisualInfo(wsDisplay, wsScreen, depth, TrueColor, &win->VisualInfo);
513
514 /* --- */
515 win->AtomLeaderClient = XInternAtom(wsDisplay, "WM_CLIENT_LEADER", False);
516 win->AtomDeleteWindow = XInternAtom(wsDisplay, "WM_DELETE_WINDOW", False);
517 win->AtomTakeFocus = XInternAtom(wsDisplay, "WM_TAKE_FOCUS", False);
518 win->AtomRolle = XInternAtom(wsDisplay, "WM_WINDOW_ROLE", False);
519 win->AtomWMSizeHint = XInternAtom(wsDisplay, "WM_SIZE_HINT", False);
520 win->AtomWMNormalHint = XInternAtom(wsDisplay, "WM_NORMAL_HINT", False);
521 win->AtomProtocols = XInternAtom(wsDisplay, "WM_PROTOCOLS", False);
522 win->AtomsProtocols[0] = win->AtomDeleteWindow;
523 win->AtomsProtocols[1] = win->AtomTakeFocus;
524 win->AtomsProtocols[2] = win->AtomRolle;
525 /* --- */
526
527 win->WindowAttrib.background_pixel = BlackPixel(wsDisplay, wsScreen);
528 win->WindowAttrib.border_pixel = WhitePixel(wsDisplay, wsScreen);
529 win->WindowAttrib.colormap = XCreateColormap(wsDisplay, wsRootWin, win->VisualInfo.visual, AllocNone);
530 win->WindowAttrib.event_mask = StructureNotifyMask | FocusChangeMask |
531 ExposureMask | PropertyChangeMask |
532 EnterWindowMask | LeaveWindowMask |
533 VisibilityChangeMask |
534 KeyPressMask | KeyReleaseMask;
535
536 if ((c & wsHandleMouseButton))
537 win->WindowAttrib.event_mask |= ButtonPressMask | ButtonReleaseMask;
538
539 if ((c & wsHandleMouseMove))
540 win->WindowAttrib.event_mask |= PointerMotionMask;
541
542 win->WindowAttrib.cursor = win->wsCursor;
543 win->WindowAttrib.override_redirect = False;
544
545 if (p & wsOverredirect)
546 win->WindowAttrib.override_redirect = True;
547
548 win->WindowMask = CWBackPixel | CWBorderPixel |
549 CWColormap | CWEventMask | CWCursor |
550 CWOverrideRedirect;
551
552 win->WindowID = XCreateWindow(wsDisplay,
553 (win->Parent != 0 ? win->Parent : wsRootWin),
554 win->X, win->Y, win->Width, win->Height, win->BorderWidth,
555 win->VisualInfo.depth,
556 InputOutput,
557 win->VisualInfo.visual,
558 win->WindowMask, &win->WindowAttrib);
559
560 wsClassHint.res_name = "MPlayer";
561
562 wsClassHint.res_class = "MPlayer";
563 XSetClassHint(wsDisplay, win->WindowID, &wsClassHint);
564
565 wsSizeHint(win);
566
567 win->WMHints.flags = InputHint | StateHint;
568 win->WMHints.input = True;
569 win->WMHints.initial_state = NormalState;
570 XSetWMHints(wsDisplay, win->WindowID, &win->WMHints);
571
572 wsWindowDecoration(win, win->Decorations);
573 XStoreName(wsDisplay, win->WindowID, label);
574 XmbSetWMProperties(wsDisplay, win->WindowID, label, label, NULL, 0, NULL, NULL, NULL);
575
576 XSetWMProtocols(wsDisplay, win->WindowID, win->AtomsProtocols, 3);
577 XChangeProperty(wsDisplay, win->WindowID,
578 win->AtomLeaderClient,
579 XA_WINDOW, 32, PropModeReplace,
580 (unsigned char *)&LeaderWindow, 1);
581
582 wsTextProperty.value = label;
583 wsTextProperty.encoding = XA_STRING;
584 wsTextProperty.format = 8;
585 wsTextProperty.nitems = strlen(label);
586 XSetWMIconName(wsDisplay, win->WindowID, &wsTextProperty);
587
588 win->wGC = XCreateGC(wsDisplay, win->WindowID,
589 GCForeground | GCBackground,
590 &win->wGCV);
591
592 win->Visible = wsNo;
593 win->Focused = wsNo;
594 win->Mapped = wsNo;
595 win->Rolled = wsNo;
596
597 if (p & wsShowWindow) {
598 XMapWindow(wsDisplay, win->WindowID);
599 wsMapWait(win);
600 }
601
602 wsCreateImage(win, win->Width, win->Height);
603 /* End of creating -------------------------------------------------------------------------- */
604
605 {
606 int i;
607
608 for (i = 0; i < wsWLCount; i++)
609 if (wsWindowList[i] == NULL)
610 break;
611
612 if (i == wsWLCount) {
613 mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_TooManyOpenWindows);
614 mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
615 }
616
617 wsWindowList[i] = win;
618 }
619
620 XFlush(wsDisplay);
621 XSync(wsDisplay, False);
622
623 win->ReDraw = NULL;
624 win->MouseHandler = NULL;
625 win->KeyHandler = NULL;
626 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] window is created. ( %s ).\n", label);
627 }
628
629 void wsWindowDecoration(wsWindow *win, Bool decor)
630 {
631 MotifWmHints wsMotifWmHints;
632
633 wsMotifHints = XInternAtom(wsDisplay, "_MOTIF_WM_HINTS", 0);
634
635 if (wsMotifHints == None)
636 return;
637
638 memset(&wsMotifWmHints, 0, sizeof(MotifWmHints));
639 wsMotifWmHints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
640
641 if (decor) {
642 wsMotifWmHints.functions = MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
643 wsMotifWmHints.decorations = MWM_DECOR_ALL;
644 }
645
646 XChangeProperty(wsDisplay, win->WindowID, wsMotifHints, wsMotifHints, 32,
647 PropModeReplace, (unsigned char *)&wsMotifWmHints, 5);
648 }
649
650 static int wsSearch(Window win)
651 {
652 int i;
653
654 for (i = 0; i < wsWLCount; i++)
655 if (wsWindowList[i] && wsWindowList[i]->WindowID == win)
656 return i;
657
658 return -1;
659 }
660
661 void wsDestroyWindow(wsWindow *win)
662 {
663 int l;
664
665 l = wsSearch(win->WindowID);
666
667 if (l != -1)
668 wsWindowList[l] = NULL;
669
670 if (win->wsCursor != None) {
671 XFreeCursor(wsDisplay, win->wsCursor);
672 win->wsCursor = None;
673 }
674
675 XFreeGC(wsDisplay, win->wGC);
676 XUnmapWindow(wsDisplay, win->WindowID);
677 wsDestroyImage(win);
678 XDestroyWindow(wsDisplay, win->WindowID);
679 #if 0
680 win->ReDraw = NULL;
681 win->MouseHandler = NULL;
682 win->KeyHandler = NULL;
683 win->Visible = wsNo;
684 win->Focused = wsNo;
685 win->Mapped = wsNo;
686 win->Rolled = wsNo;
687 #endif
688 }
689
690 /**
691 * @brief Handle automatic hiding of the cursor.
692 */
693 void wsAutohideCursor(void)
694 {
695 if (mouse_win && (GetTimerMS() - mouse_time >= MOUSEHIDE_DELAY)) {
696 wsVisibleMouse(mouse_win, wsHideMouseCursor);
697 mouse_win = NULL;
698 }
699 }
700
701 // ----------------------------------------------------------------------------------------------
702 // Handle events.
703 // ----------------------------------------------------------------------------------------------
704
705 void wsEvents(XEvent *event)
706 {
707 unsigned long i = 0;
708 int l;
709 int x, y;
710 Window child_window = 0;
711
712 l = wsSearch(event->xany.window);
713
714 if (l == -1)
715 return;
716
717 wsWindowList[l]->State = wsNone;
718
719 switch (event->type) {
720 case ClientMessage:
721
722 if (event->xclient.message_type == wsWindowList[l]->AtomProtocols) {
723 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomDeleteWindow) {
724 i = wsWindowClosed;
725 goto expose;
726 }
727
728 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomTakeFocus) {
729 i = wsWindowFocusIn;
730 wsWindowList[l]->Focused = wsFocused;
731 goto expose;
732 }
733
734 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomRolle) {
735 mp_msg(MSGT_GPLAYER, MSGL_V, "[ws] role set.\n");
736 }
737 } else {
738 /* try to process DND events */
739 wsXDNDProcessClientMessage(&event->xclient);
740 }
741
742 break;
743
744 case MapNotify:
745
746 i = wsWindowMapped;
747 wsWindowList[l]->Mapped = wsMapped;
748 goto expose;
749
750 case UnmapNotify:
751
752 i = wsWindowUnmapped;
753 wsWindowList[l]->Mapped = wsNo;
754 goto expose;
755
756 case FocusIn:
757
758 if (wsWindowList[l]->Focused == wsFocused)
759 break;
760
761 i = wsWindowFocusIn;
762 wsWindowList[l]->Focused = wsFocused;
763 goto expose;
764
765 case FocusOut:
766
767 if (wsWindowList[l]->Focused == wsNo)
768 break;
769
770 i = wsWindowFocusOut;
771 wsWindowList[l]->Focused = wsNo;
772 goto expose;
773
774 case VisibilityNotify:
775
776 switch (event->xvisibility.state) {
777 case VisibilityUnobscured:
778 i = wsWindowVisible;
779 wsWindowList[l]->Visible = wsVisible;
780 goto expose;
781
782 case VisibilityFullyObscured:
783 i = wsWindowNotVisible;
784 wsWindowList[l]->Visible = wsNotVisible;
785 goto expose;
786
787 case VisibilityPartiallyObscured:
788 i = wsWindowPartialVisible;
789 wsWindowList[l]->Visible = wsPVisible;
790 goto expose;
791 }
792
793 expose:
794 wsWindowList[l]->State = i;
795
796 if (wsWindowList[l]->ReDraw)
797 wsWindowList[l]->ReDraw();
798
799 break;
800
801 case Expose:
802
803 wsWindowList[l]->State = wsWindowExpose;
804
805 if ((wsWindowList[l]->ReDraw) && (!event->xexpose.count))
806 wsWindowList[l]->ReDraw();
807
808 break;
809
810 case ConfigureNotify:
811
812 XTranslateCoordinates(wsDisplay, wsWindowList[l]->WindowID, wsRootWin, 0, 0, &x, &y, &child_window);
813
814 if ((wsWindowList[l]->X != x) || (wsWindowList[l]->Y != y) || (wsWindowList[l]->Width != event->xconfigure.width) || (wsWindowList[l]->Height != event->xconfigure.height)) {
815 wsWindowList[l]->X = x;
816 wsWindowList[l]->Y = y;
817 wsWindowList[l]->Width = event->xconfigure.width;
818 wsWindowList[l]->Height = event->xconfigure.height;
819 }
820
821 wsWindowList[l]->Rolled = wsNo;
822
823 if (event->xconfigure.y < 0) {
824 i = wsWindowRolled;
825 wsWindowList[l]->Rolled = wsRolled;
826 goto expose;
827 }
828
829 break;
830
831 case KeyPress:
832
833 i = wsKeyPressed;
834 goto keypressed;
835
836 case KeyRelease:
837
838 i = wsKeyReleased;
839 keypressed:
840 wsWindowList[l]->Alt = False;
841 wsWindowList[l]->Shift = False;
842 wsWindowList[l]->NumLock = False;
843 wsWindowList[l]->Control = False;
844 wsWindowList[l]->CapsLock = False;
845
846 if (event->xkey.state & Mod1Mask)
847 wsWindowList[l]->Alt = True;
848
849 if (event->xkey.state & Mod2Mask)
850 wsWindowList[l]->NumLock = True;
851
852 if (event->xkey.state & ControlMask)
853 wsWindowList[l]->Control = True;
854
855 if (event->xkey.state & ShiftMask)
856 wsWindowList[l]->Shift = True;
857
858 if (event->xkey.state & LockMask)
859 wsWindowList[l]->CapsLock = True;
860
861 #if 0
862 {
863 KeySym keySym;
864 keySym = XKeycodeToKeysym(wsDisplay, event->xkey.keycode, 0);
865
866 if (keySym != NoSymbol) {
867 keySym = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym));
868
869 if (wsWindowList[l]->KeyHandler)
870 wsWindowList[l]->KeyHandler(event->xkey.state, i, keySym);
871 }
872 }
873 #else
874 {
875 int key;
876 char buf[100];
877 KeySym keySym;
878 static XComposeStatus stat;
879
880 XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat);
881 key = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym));
882
883 if (wsWindowList[l]->KeyHandler)
884 wsWindowList[l]->KeyHandler(event->xkey.keycode, i, key);
885 }
886 #endif
887 break;
888
889 case MotionNotify:
890
891 i = wsMoveMouse;
892 {
893 /* pump all motion events from the display queue:
894 * this way it works faster when moving the window */
895 static XEvent e;
896
897 if (event->xmotion.state) {
898 while (XCheckTypedWindowEvent(wsDisplay, event->xany.window, MotionNotify, &e)) {
899 /* FIXME: need to make sure we didn't release/press the button in between...*/
900 /* FIXME: do we need some timeout here to make sure we don't spend too much time
901 * removing events from the queue? */
902 event = &e;
903 }
904 }
905 }
906
907 if (wsWindowList[l]->wsCursor != None) {
908 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
909 mouse_win = wsWindowList[l];
910 mouse_time = GetTimerMS();
911 }
912
913 goto buttonreleased;
914
915 case ButtonRelease:
916
917 i = event->xbutton.button + 128;
918
919 if (wsWindowList[l]->wsCursor != None) {
920 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
921 mouse_win = wsWindowList[l];
922 mouse_time = GetTimerMS();
923 }
924
925 goto buttonreleased;
926
927 case ButtonPress:
928
929 i = event->xbutton.button;
930
931 if (wsWindowList[l]->wsCursor != None) {
932 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
933 mouse_win = wsWindowList[l];
934 mouse_time = GetTimerMS();
935 }
936
937 goto buttonreleased;
938
939 case EnterNotify:
940
941 i = wsEnterWindow;
942 goto buttonreleased;
943
944 case LeaveNotify:
945
946 i = wsLeaveWindow;
947 buttonreleased:
948
949 if (wsWindowList[l]->MouseHandler)
950 wsWindowList[l]->MouseHandler(i, event->xbutton.x, event->xbutton.y, event->xmotion.x_root, event->xmotion.y_root);
951
952 break;
953
954 case SelectionNotify:
955
956 /* Handle DandD */
957 wsXDNDProcessSelection(wsWindowList[l], event);
958 break;
959 }
960
961 XFlush(wsDisplay);
962 XSync(wsDisplay, False);
963 }
964
965 void wsHandleEvents(void)
966 {
967 XEvent wsEvent;
968 /* handle pending events */
969 while (XPending(wsDisplay)) {
970 XNextEvent(wsDisplay, &wsEvent);
971 // printf("### X event: %d [%d]\n",wsEvent.type,delay);
972 wsEvents(&wsEvent);
973 }
974 }
975
976 // ----------------------------------------------------------------------------------------------
977 // Move window to selected layer
978 // ----------------------------------------------------------------------------------------------
979
980 /**
981 * @brief Set the layer for a window.
982 *
983 * @param display display
984 * @param Win window
985 * @param fullscreen whether to set fullscreen or normal layer
986 */
987 void wsSetLayer(Display *display, Window Win, Bool fullscreen)
988 {
989 vo_x11_setlayer(display, Win, fullscreen);
990 }
991
992 /**
993 * @brief Switch window fullscreen state.
994 *
995 * Switch normal window to fullscreen and fullscreen window to normal.
996 *
997 * @param win pointer to a ws window structure
998 */
999 void wsFullScreen(wsWindow *win)
1000 {
1001 if (win->isFullScreen) {
1002 if (vo_fs_type & vo_wm_FULLSCREEN)
1003 /* window manager supports EWMH */
1004 vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_REMOVE);
1005 else {
1006 win->X = win->OldX;
1007 win->Y = win->OldY;
1008 win->Width = win->OldWidth;
1009 win->Height = win->OldHeight;
1010 }
1011
1012 win->isFullScreen = False;
1013 } else {
1014 if (vo_fs_type & vo_wm_FULLSCREEN)
1015 /* window manager supports EWMH */
1016 vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_ADD);
1017 else {
1018 win->OldX = win->X;
1019 win->OldY = win->Y;
1020 win->OldWidth = win->Width;
1021 win->OldHeight = win->Height;
1022 }
1023
1024 win->isFullScreen = True;
1025
1026 wsUpdateXineramaInfo(win);
1027 }
1028
1029 /* unknown window manager and obsolete option -fsmode used */
1030 if (vo_wm_type == 0 && !(vo_fsmode & 16)) {
1031 XUnmapWindow(wsDisplay, win->WindowID); // required for MWM
1032 XWithdrawWindow(wsDisplay, win->WindowID, wsScreen);
1033 }
1034
1035 /* restore window if window manager doesn't support EWMH */
1036 if (!(vo_fs_type & vo_wm_FULLSCREEN)) {
1037 wsSizeHint(win);
1038 wsWindowDecoration(win, win->Decorations && !win->isFullScreen);
1039 wsSetLayer(wsDisplay, win->WindowID, win->isFullScreen);
1040 XMoveResizeWindow(wsDisplay, win->WindowID, win->X, win->Y, win->Width, win->Height);
1041 }
1042
1043 /* some window managers lose ontop after fullscreen */
1044 if (!win->isFullScreen & vo_ontop)
1045 wsSetLayer(wsDisplay, win->WindowID, vo_ontop);
1046
1047 wsRaiseWindowTop(wsDisplay, win->WindowID);
1048 XFlush(wsDisplay);
1049 }
1050
1051 // ----------------------------------------------------------------------------------------------
1052 // Redraw screen.
1053 // ----------------------------------------------------------------------------------------------
1054 void wsPostRedisplay(wsWindow *win)
1055 {
1056 if (win->ReDraw) {
1057 win->State = wsWindowExpose;
1058 win->ReDraw();
1059 XFlush(wsDisplay);
1060 }
1061 }
1062
1063 // ----------------------------------------------------------------------------------------------
1064 // Put 'Image' to window.
1065 // ----------------------------------------------------------------------------------------------
1066 void wsConvert(wsWindow *win, unsigned char *Image)
1067 {
1068 static struct SwsContext *sws_ctx;
1069 const uint8_t *src[4] = { Image, NULL, NULL, NULL };
1070 int src_stride[4] = { 4 * win->xImage->width, 0, 0, 0 };
1071 uint8_t *dst[4] = { win->ImageData, NULL, NULL, NULL };
1072 int dst_stride[4];
1073 int i;
1074
1075 sws_ctx = sws_getCachedContext(sws_ctx, win->xImage->width, win->xImage->height, PIX_FMT_RGB32,
1076 win->xImage->width, win->xImage->height, out_pix_fmt,
1077 SWS_POINT, NULL, NULL, NULL);
1078 av_image_fill_linesizes(dst_stride, out_pix_fmt, win->xImage->width);
1079 sws_scale(sws_ctx, src, src_stride, 0, win->xImage->height, dst, dst_stride);
1080
1081 if (!wsNonNativeOrder)
1082 return;
1083
1084 switch (win->xImage->bits_per_pixel) {
1085 case 32:
1086 {
1087 uint32_t *d = (uint32_t *)win->ImageData;
1088
1089 for (i = 0; i < win->xImage->width * win->xImage->height; i++)
1090 d[i] = bswap_32(d[i]);
1091
1092 break;
1093 }
1094
1095 case 16:
1096 case 15:
1097 {
1098 uint16_t *d = (uint16_t *)win->ImageData;
1099
1100 for (i = 0; i < win->xImage->width * win->xImage->height; i++)
1101 d[i] = bswap_16(d[i]);
1102
1103 break;
1104 }
1105 }
1106 }
1107
1108 void wsPutImage(wsWindow *win)
1109 {
1110 #ifdef HAVE_SHM
1111 if (wsUseXShm) {
1112 XShmPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage,
1113 0, 0,
1114 (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2,
1115 win->xImage->width, win->xImage->height, 0);
1116 } else
1117 #endif
1118 {
1119 XPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage,
1120 0, 0,
1121 (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2,
1122 win->xImage->width, win->xImage->height);
1123 }
1124 }
1125
1126 // ----------------------------------------------------------------------------------------------
1127 // Move window to x, y.
1128 // ----------------------------------------------------------------------------------------------
1129 void wsMoveWindow(wsWindow *win, Bool abs, int x, int y)
1130 {
1131 if (abs) {
1132 win->X = x;
1133 win->Y = y;
1134 } else
1135 wsWindowPosition(win, x, y, win->Width, win->Height);
1136
1137 wsSizeHint(win);
1138 XMoveWindow(wsDisplay, win->WindowID, win->X, win->Y);
1139 }
1140
1141 /**
1142 * @brief Move the window to the x and y position, but if it no longer fits
1143 * into the screen, reposition it towards the upper left.
1144 *
1145 * @param win pointer to a ws window structure
1146 * @param abs flag whether the position is real/absolute (True) or mock (False)
1147 * @param x x position of the window (real/absolute or mock)
1148 * @param y y position of the window (real/absolute or mock)
1149 */
1150 void wsMoveWindowWithin(wsWindow *win, Bool abs, int x, int y)
1151 {
1152 Bool fitting = True;
1153
1154 wsMoveWindow(win, abs, x, y);
1155
1156 if (win->X + win->Width + 1 > wsMaxX) {
1157 fitting = False;
1158 win->X = wsMaxX - win->Width;
1159
1160 if (win->X < 0)
1161 win->X = 0;
1162 }
1163
1164 if (win->Y + win->Height + 1 > wsMaxY) {
1165 fitting = False;
1166 win->Y = wsMaxY - win->Height;
1167
1168 if (win->Y < 0)
1169 win->Y = 0;
1170 }
1171
1172 if (!fitting)
1173 wsMoveWindow(win, True, win->X, win->Y);
1174 }
1175
1176 // ----------------------------------------------------------------------------------------------
1177 // Resize window to sx, sy.
1178 // ----------------------------------------------------------------------------------------------
1179 void wsResizeWindow(wsWindow *win, int sx, int sy)
1180 {
1181 win->Width = sx;
1182 win->Height = sy;
1183
1184 if (vo_wm_type == 0)
1185 XUnmapWindow(wsDisplay, win->WindowID);
1186
1187 wsSizeHint(win);
1188 XResizeWindow(wsDisplay, win->WindowID, sx, sy);
1189
1190 if (vo_wm_type == 0)
1191 XMapWindow(wsDisplay, win->WindowID);
1192 }
1193
1194 /**
1195 * @brief Iconify a window.
1196 *
1197 * @param win pointer to a ws window structure
1198 */
1199 void wsIconify(wsWindow *win)
1200 {
1201 XIconifyWindow(wsDisplay, win->WindowID, 0);
1202 }
1203
1204 /**
1205 * @brief Map a window and raise it to the top.
1206 *
1207 * @param display display
1208 * @param Win window
1209 */
1210 void wsRaiseWindowTop(Display *display, Window Win)
1211 {
1212 XMapRaised(display, Win); // NOTE TO MYSELF: is that really enough?
1213 XRaiseWindow(display, Win); // NOTE TO MYSELF: is that really enough?
1214 }
1215
1216 // ----------------------------------------------------------------------------------------------
1217 // Set window background to 'color'.
1218 // ----------------------------------------------------------------------------------------------
1219 void wsSetBackgroundRGB(wsWindow *win, int r, int g, int b)
1220 {
1221 int color = 0;
1222
1223 switch (wsOutMask) {
1224 case wsRGB32:
1225 case wsRGB24:
1226 color = (r << 16) + (g << 8) + b;
1227 break;
1228
1229 case wsBGR32:
1230 case wsBGR24:
1231 color = (b << 16) + (g << 8) + r;
1232 break;
1233
1234 case wsRGB16:
1235 PACK_RGB16(b, g, r, color);
1236 break;
1237
1238 case wsBGR16:
1239 PACK_RGB16(r, g, b, color);
1240 break;
1241
1242 case wsRGB15:
1243 PACK_RGB15(b, g, r, color);
1244 break;
1245
1246 case wsBGR15:
1247 PACK_RGB15(r, g, b, color);
1248 break;
1249 }
1250
1251 XSetWindowBackground(wsDisplay, win->WindowID, color);
1252 }
1253
1254 // ----------------------------------------------------------------------------------------------
1255 // Show / hide mouse cursor.
1256 // ----------------------------------------------------------------------------------------------
1257 void wsVisibleMouse(wsWindow *win, int m)
1258 {
1259 switch (m) {
1260 case wsShowMouseCursor:
1261
1262 if (win->wsCursor != None) {
1263 XFreeCursor(wsDisplay, win->wsCursor);
1264 win->wsCursor = None;
1265 }
1266
1267 XDefineCursor(wsDisplay, win->WindowID, 0);
1268 break;
1269
1270 case wsHideMouseCursor:
1271
1272 win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0);
1273 XDefineCursor(wsDisplay, win->WindowID, win->wsCursor);
1274 break;
1275 }
1276
1277 XFlush(wsDisplay);
1278 } 166 }
1279 167
1280 int wsGetDepthOnScreen(void) 168 int wsGetDepthOnScreen(void)
1281 { 169 {
1282 int depth; 170 int depth;
1319 } 207 }
1320 208
1321 return wsDepthOnScreen; 209 return wsDepthOnScreen;
1322 } 210 }
1323 211
212 int wsGetOutMask(void)
213 {
214 if ((wsDepthOnScreen == 32) && (wsRedMask == 0xff0000) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0x0000ff))
215 return wsRGB32;
216
217 if ((wsDepthOnScreen == 32) && (wsRedMask == 0x0000ff) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0xff0000))
218 return wsBGR32;
219
220 if ((wsDepthOnScreen == 24) && (wsRedMask == 0xff0000) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0x0000ff))
221 return wsRGB24;
222
223 if ((wsDepthOnScreen == 24) && (wsRedMask == 0x0000ff) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0xff0000))
224 return wsBGR24;
225
226 if ((wsDepthOnScreen == 16) && (wsRedMask == 0xf800) && (wsGreenMask == 0x7e0) && (wsBlueMask == 0x1f))
227 return wsRGB16;
228
229 if ((wsDepthOnScreen == 16) && (wsRedMask == 0x1f) && (wsGreenMask == 0x7e0) && (wsBlueMask == 0xf800))
230 return wsBGR16;
231
232 if ((wsDepthOnScreen == 15) && (wsRedMask == 0x7c00) && (wsGreenMask == 0x3e0) && (wsBlueMask == 0x1f))
233 return wsRGB15;
234
235 if ((wsDepthOnScreen == 15) && (wsRedMask == 0x1f) && (wsGreenMask == 0x3e0) && (wsBlueMask == 0x7c00))
236 return wsBGR15;
237
238 return 0;
239 }
240
241 void wsXInit(Display *display)
242 {
243 int eventbase;
244 int errorbase;
245
246 mp_msg(MSGT_GPLAYER, MSGL_V, "X init.\n");
247
248 wsDisplay = display;
249
250 wsSetErrorHandler();
251
252 /* enable DND atoms */
253 wsXDNDInitialize();
254
255 { /* on remote display XShm will be disabled - LGB */
256 char *dispname = DisplayString(wsDisplay);
257 int localdisp = 1;
258
259 if (dispname && *dispname != ':') {
260 localdisp = 0;
261 wsUseXShm = False;
262 }
263
264 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] display name: %s => %s display.\n", dispname, localdisp ? "local" : "REMOTE");
265
266 if (!localdisp)
267 mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_RemoteDisplay);
268 }
269
270 #ifdef HAVE_SHM
271 if (!XShmQueryExtension(wsDisplay))
272 #endif
273 wsUseXShm = False;
274
275 if (!wsUseXShm)
276 mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_NoXshm);
277
278 #ifdef CONFIG_XSHAPE
279 if (!XShapeQueryExtension(wsDisplay, &eventbase, &errorbase))
280 #endif
281 wsUseXShape = False;
282
283 if (!wsUseXShape)
284 mp_msg(MSGT_GPLAYER, MSGL_WARN, MSGTR_WS_NoXshape);
285
286 XSynchronize(wsDisplay, True);
287
288 wsScreen = DefaultScreen(wsDisplay);
289 wsRootWin = RootWindow(wsDisplay, wsScreen);
290 #ifdef CONFIG_XF86VM
291 {
292 int clock;
293 XF86VidModeModeLine modeline;
294
295 XF86VidModeGetModeLine(wsDisplay, wsScreen, &clock, &modeline);
296 wsMaxX = modeline.hdisplay;
297 wsMaxY = modeline.vdisplay;
298 }
299 #endif
300 {
301 wsOrgX = wsOrgY = 0;
302
303 if (!wsMaxX)
304 wsMaxX = DisplayWidth(wsDisplay, wsScreen);
305
306 if (!wsMaxY)
307 wsMaxY = DisplayHeight(wsDisplay, wsScreen);
308 }
309
310 wsUpdateXineramaInfo(NULL);
311
312 wsGetDepthOnScreen();
313
314 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Screen depth: %d\n", wsDepthOnScreen);
315 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] size: %dx%d\n", wsMaxX, wsMaxY);
316
317 #ifdef CONFIG_XINERAMA
318 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] origin: +%d+%d\n", wsOrgX, wsOrgY);
319 #endif
320
321 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] red mask: 0x%x\n", wsRedMask);
322 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] green mask: 0x%x\n", wsGreenMask);
323 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] blue mask: 0x%x\n", wsBlueMask);
324
325 #ifdef HAVE_SHM
326 if (wsUseXShm) {
327 int minor, major, shp;
328
329 XShmQueryVersion(wsDisplay, &major, &minor, &shp);
330 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShm version is %d.%d\n", major, minor);
331 }
332 #endif
333
334 #ifdef CONFIG_XSHAPE
335 if (wsUseXShape) {
336 int minor, major;
337
338 XShapeQueryVersion(wsDisplay, &major, &minor);
339 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShape version is %d.%d\n", major, minor);
340 }
341 #endif
342
343 wsOutMask = wsGetOutMask();
344
345 switch (wsOutMask) {
346 case wsRGB32:
347 out_pix_fmt = PIX_FMT_RGB32;
348 break;
349
350 case wsBGR32:
351 out_pix_fmt = PIX_FMT_BGR32;
352 break;
353
354 case wsRGB24:
355 out_pix_fmt = PIX_FMT_RGB24;
356 break;
357
358 case wsBGR24:
359 out_pix_fmt = PIX_FMT_BGR24;
360 break;
361
362 case wsRGB16:
363 out_pix_fmt = PIX_FMT_RGB565;
364 break;
365
366 case wsBGR16:
367 out_pix_fmt = PIX_FMT_BGR565;
368 break;
369
370 case wsRGB15:
371 out_pix_fmt = PIX_FMT_RGB555;
372 break;
373
374 case wsBGR15:
375 out_pix_fmt = PIX_FMT_BGR555;
376 break;
377 }
378 }
379
1324 void wsXDone(void) 380 void wsXDone(void)
1325 { 381 {
1326 XCloseDisplay(wsDisplay); 382 XCloseDisplay(wsDisplay);
383 }
384
385 /**
386 * @brief Inform about an X error that has occurred.
387 *
388 * @param display display
389 * @param event pointer to an X error event structure
390 *
391 * @return 0
392 */
393 static int wsErrorHandler(Display *display, XErrorEvent *event)
394 {
395 char type[128];
396
397 XGetErrorText(display, event->error_code, type, sizeof(type));
398
399 mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] " MSGTR_WS_XError);
400 mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] Error code: %d - %s\n", event->error_code, type);
401 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Request code: %d (minor code: %d)\n", event->request_code, event->minor_code);
402 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] MPlayer module: %s\n", current_module ? current_module : "(none)");
403
404 return 0;
405 }
406
407 /**
408 * @brief Set the X error handler.
409 */
410 void wsSetErrorHandler(void)
411 {
412 XSetErrorHandler(wsErrorHandler);
413 }
414
415 // ----------------------------------------------------------------------------------------------
416 // Handle events.
417 // ----------------------------------------------------------------------------------------------
418
419 static int wsSearch(Window win)
420 {
421 int i;
422
423 for (i = 0; i < wsWLCount; i++)
424 if (wsWindowList[i] && wsWindowList[i]->WindowID == win)
425 return i;
426
427 return -1;
428 }
429
430 void wsEvents(XEvent *event)
431 {
432 unsigned long i = 0;
433 int l;
434 int x, y;
435 Window child_window = 0;
436
437 l = wsSearch(event->xany.window);
438
439 if (l == -1)
440 return;
441
442 wsWindowList[l]->State = wsNone;
443
444 switch (event->type) {
445 case ClientMessage:
446
447 if (event->xclient.message_type == wsWindowList[l]->AtomProtocols) {
448 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomDeleteWindow) {
449 i = wsWindowClosed;
450 goto expose;
451 }
452
453 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomTakeFocus) {
454 i = wsWindowFocusIn;
455 wsWindowList[l]->Focused = wsFocused;
456 goto expose;
457 }
458
459 if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomRolle) {
460 mp_msg(MSGT_GPLAYER, MSGL_V, "[ws] role set.\n");
461 }
462 } else {
463 /* try to process DND events */
464 wsXDNDProcessClientMessage(&event->xclient);
465 }
466
467 break;
468
469 case MapNotify:
470
471 i = wsWindowMapped;
472 wsWindowList[l]->Mapped = wsMapped;
473 goto expose;
474
475 case UnmapNotify:
476
477 i = wsWindowUnmapped;
478 wsWindowList[l]->Mapped = wsNo;
479 goto expose;
480
481 case FocusIn:
482
483 if (wsWindowList[l]->Focused == wsFocused)
484 break;
485
486 i = wsWindowFocusIn;
487 wsWindowList[l]->Focused = wsFocused;
488 goto expose;
489
490 case FocusOut:
491
492 if (wsWindowList[l]->Focused == wsNo)
493 break;
494
495 i = wsWindowFocusOut;
496 wsWindowList[l]->Focused = wsNo;
497 goto expose;
498
499 case VisibilityNotify:
500
501 switch (event->xvisibility.state) {
502 case VisibilityUnobscured:
503 i = wsWindowVisible;
504 wsWindowList[l]->Visible = wsVisible;
505 goto expose;
506
507 case VisibilityFullyObscured:
508 i = wsWindowNotVisible;
509 wsWindowList[l]->Visible = wsNotVisible;
510 goto expose;
511
512 case VisibilityPartiallyObscured:
513 i = wsWindowPartialVisible;
514 wsWindowList[l]->Visible = wsPVisible;
515 goto expose;
516 }
517
518 expose:
519 wsWindowList[l]->State = i;
520
521 if (wsWindowList[l]->ReDraw)
522 wsWindowList[l]->ReDraw();
523
524 break;
525
526 case Expose:
527
528 wsWindowList[l]->State = wsWindowExpose;
529
530 if ((wsWindowList[l]->ReDraw) && (!event->xexpose.count))
531 wsWindowList[l]->ReDraw();
532
533 break;
534
535 case ConfigureNotify:
536
537 XTranslateCoordinates(wsDisplay, wsWindowList[l]->WindowID, wsRootWin, 0, 0, &x, &y, &child_window);
538
539 if ((wsWindowList[l]->X != x) || (wsWindowList[l]->Y != y) || (wsWindowList[l]->Width != event->xconfigure.width) || (wsWindowList[l]->Height != event->xconfigure.height)) {
540 wsWindowList[l]->X = x;
541 wsWindowList[l]->Y = y;
542 wsWindowList[l]->Width = event->xconfigure.width;
543 wsWindowList[l]->Height = event->xconfigure.height;
544 }
545
546 wsWindowList[l]->Rolled = wsNo;
547
548 if (event->xconfigure.y < 0) {
549 i = wsWindowRolled;
550 wsWindowList[l]->Rolled = wsRolled;
551 goto expose;
552 }
553
554 break;
555
556 case KeyPress:
557
558 i = wsKeyPressed;
559 goto keypressed;
560
561 case KeyRelease:
562
563 i = wsKeyReleased;
564 keypressed:
565 wsWindowList[l]->Alt = False;
566 wsWindowList[l]->Shift = False;
567 wsWindowList[l]->NumLock = False;
568 wsWindowList[l]->Control = False;
569 wsWindowList[l]->CapsLock = False;
570
571 if (event->xkey.state & Mod1Mask)
572 wsWindowList[l]->Alt = True;
573
574 if (event->xkey.state & Mod2Mask)
575 wsWindowList[l]->NumLock = True;
576
577 if (event->xkey.state & ControlMask)
578 wsWindowList[l]->Control = True;
579
580 if (event->xkey.state & ShiftMask)
581 wsWindowList[l]->Shift = True;
582
583 if (event->xkey.state & LockMask)
584 wsWindowList[l]->CapsLock = True;
585
586 #if 0
587 {
588 KeySym keySym;
589 keySym = XKeycodeToKeysym(wsDisplay, event->xkey.keycode, 0);
590
591 if (keySym != NoSymbol) {
592 keySym = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym));
593
594 if (wsWindowList[l]->KeyHandler)
595 wsWindowList[l]->KeyHandler(event->xkey.state, i, keySym);
596 }
597 }
598 #else
599 {
600 int key;
601 char buf[100];
602 KeySym keySym;
603 static XComposeStatus stat;
604
605 XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat);
606 key = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym));
607
608 if (wsWindowList[l]->KeyHandler)
609 wsWindowList[l]->KeyHandler(event->xkey.keycode, i, key);
610 }
611 #endif
612 break;
613
614 case MotionNotify:
615
616 i = wsMoveMouse;
617 {
618 /* pump all motion events from the display queue:
619 * this way it works faster when moving the window */
620 static XEvent e;
621
622 if (event->xmotion.state) {
623 while (XCheckTypedWindowEvent(wsDisplay, event->xany.window, MotionNotify, &e)) {
624 /* FIXME: need to make sure we didn't release/press the button in between...*/
625 /* FIXME: do we need some timeout here to make sure we don't spend too much time
626 * removing events from the queue? */
627 event = &e;
628 }
629 }
630 }
631
632 if (wsWindowList[l]->wsCursor != None) {
633 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
634 mouse_win = wsWindowList[l];
635 mouse_time = GetTimerMS();
636 }
637
638 goto buttonreleased;
639
640 case ButtonRelease:
641
642 i = event->xbutton.button + 128;
643
644 if (wsWindowList[l]->wsCursor != None) {
645 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
646 mouse_win = wsWindowList[l];
647 mouse_time = GetTimerMS();
648 }
649
650 goto buttonreleased;
651
652 case ButtonPress:
653
654 i = event->xbutton.button;
655
656 if (wsWindowList[l]->wsCursor != None) {
657 wsVisibleMouse(wsWindowList[l], wsShowMouseCursor);
658 mouse_win = wsWindowList[l];
659 mouse_time = GetTimerMS();
660 }
661
662 goto buttonreleased;
663
664 case EnterNotify:
665
666 i = wsEnterWindow;
667 goto buttonreleased;
668
669 case LeaveNotify:
670
671 i = wsLeaveWindow;
672 buttonreleased:
673
674 if (wsWindowList[l]->MouseHandler)
675 wsWindowList[l]->MouseHandler(i, event->xbutton.x, event->xbutton.y, event->xmotion.x_root, event->xmotion.y_root);
676
677 break;
678
679 case SelectionNotify:
680
681 /* Handle DandD */
682 wsXDNDProcessSelection(wsWindowList[l], event);
683 break;
684 }
685
686 XFlush(wsDisplay);
687 XSync(wsDisplay, False);
688 }
689
690 void wsHandleEvents(void)
691 {
692 XEvent wsEvent;
693 /* handle pending events */
694 while (XPending(wsDisplay)) {
695 XNextEvent(wsDisplay, &wsEvent);
696 // printf("### X event: %d [%d]\n",wsEvent.type,delay);
697 wsEvents(&wsEvent);
698 }
699 }
700
701 /**
702 * @brief Calculate and store the x and y position for a window.
703 *
704 * @param win pointer to a ws window structure
705 * @param x x position of the window (real/absolute or mock)
706 * @param y y position of the window (real/absolute or mock)
707 * @param width width of the area to place the window in
708 * @param height height of the area to place the window in
709 */
710 static void wsWindowPosition(wsWindow *win, int x, int y, int width, int height)
711 {
712 switch (x) {
713 case -1:
714 win->X = wsOrgX + (wsMaxX - width) / 2;
715 break;
716
717 case -2:
718 win->X = wsOrgX + wsMaxX - width;
719 break;
720
721 default:
722 win->X = x;
723 break;
724 }
725
726 switch (y) {
727 case -1:
728 win->Y = wsOrgY + (wsMaxY - height) / 2;
729 break;
730
731 case -2:
732 win->Y = wsOrgY + wsMaxY - height;
733 break;
734
735 default:
736 win->Y = y;
737 break;
738 }
739 }
740
741 /**
742 * @brief Replace the size hints for the WM_NORMAL_HINTS property of a window.
743 *
744 * @param win pointer to a ws window structure
745 */
746 static void wsSizeHint(wsWindow *win)
747 {
748 XSizeHints size;
749
750 size.flags = 0;
751
752 /* obsolete, solely for compatibility reasons */
753 size.flags |= PPosition;
754 size.x = win->X;
755 size.y = win->Y;
756
757 /* obsolete, solely for compatibility reasons */
758 size.flags |= PSize;
759 size.width = win->Width;
760 size.height = win->Height;
761
762 /* a minimum of 4 is said to avoid off-by-one errors and be required by mga_vid */
763 size.flags |= PMinSize;
764 size.min_width = 4;
765 size.min_height = 4;
766
767 if (win->Property & wsMinSize) {
768 size.min_width = win->Width;
769 size.min_height = win->Height;
770 }
771
772 if (win->Property & wsMaxSize) {
773 size.flags |= PMaxSize;
774 size.max_width = win->Width;
775 size.max_height = win->Height;
776 }
777
778 if (vo_keepaspect && (win->Property & wsAspect)) {
779 size.flags |= PAspect;
780 size.min_aspect.x = win->Width;
781 size.min_aspect.y = win->Height;
782 size.max_aspect.x = win->Width;
783 size.max_aspect.y = win->Height;
784 }
785
786 size.flags |= PBaseSize;
787 size.base_width = 0;
788 size.base_height = 0;
789
790 size.flags |= PWinGravity;
791 size.win_gravity = StaticGravity;
792
793 XSetWMNormalHints(wsDisplay, win->WindowID, &size);
794 }
795
796 /**
797 * @brief Wait until a window is mapped if its property requires it.
798 *
799 * @param win pointer to a ws window structure
800 */
801 static void wsMapWait(wsWindow *win)
802 {
803 XEvent xev;
804
805 if (win->Property & wsWaitMap) {
806 do
807 XNextEvent(wsDisplay, &xev);
808 while (xev.type != MapNotify || xev.xmap.event != win->WindowID);
809
810 win->Mapped = wsMapped;
811 }
812 }
813
814 // ----------------------------------------------------------------------------------------------
815 // Create window.
816 // X,Y : window position
817 // wX,wY : size of window
818 // bW : border width
819 // cV : visible mouse cursor on window
820 // D : visible frame, title, etc.
821 // sR : screen ratio
822 // ----------------------------------------------------------------------------------------------
823
824 XClassHint wsClassHint;
825 XTextProperty wsTextProperty;
826 Window LeaderWindow;
827
828 // ----------------------------------------------------------------------------------------------
829 // wsCreateWindow: create a new window on the screen.
830 // x,y : window position
831 // w,h : window size
832 // b : window border size
833 // c : mouse cursor visible
834 // p : properties - "decoration", visible titlebar, etc ...
835 // ----------------------------------------------------------------------------------------------
836 void wsCreateWindow(wsWindow *win, int x, int y, int w, int h, int b, int c, unsigned char p, char *label)
837 {
838 int depth;
839
840 win->Property = p;
841
842 if (p & wsShowFrame)
843 win->Decorations = True;
844
845 wsWindowPosition(win, x, y, w, h);
846
847 win->Width = w;
848 win->Height = h;
849 win->OldX = win->X;
850 win->OldY = win->Y;
851 win->OldWidth = win->Width;
852 win->OldHeight = win->Height;
853
854 /* Border size for window. */
855 win->BorderWidth = b;
856 /* Hide Mouse Cursor */
857 win->wsCursor = None;
858 win->wsMouseEventType = c;
859 win->wsCursorData[0] = 0;
860 win->wsCursorPixmap = XCreateBitmapFromData(wsDisplay, wsRootWin, win->wsCursorData, 1, 1);
861
862 if (!(c & wsShowMouseCursor))
863 win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0);
864
865 depth = vo_find_depth_from_visuals(wsDisplay, wsScreen, NULL);
866
867 if (depth < 15) {
868 mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ColorDepthTooLow);
869 mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
870 }
871
872 XMatchVisualInfo(wsDisplay, wsScreen, depth, TrueColor, &win->VisualInfo);
873
874 /* --- */
875 win->AtomLeaderClient = XInternAtom(wsDisplay, "WM_CLIENT_LEADER", False);
876 win->AtomDeleteWindow = XInternAtom(wsDisplay, "WM_DELETE_WINDOW", False);
877 win->AtomTakeFocus = XInternAtom(wsDisplay, "WM_TAKE_FOCUS", False);
878 win->AtomRolle = XInternAtom(wsDisplay, "WM_WINDOW_ROLE", False);
879 win->AtomWMSizeHint = XInternAtom(wsDisplay, "WM_SIZE_HINT", False);
880 win->AtomWMNormalHint = XInternAtom(wsDisplay, "WM_NORMAL_HINT", False);
881 win->AtomProtocols = XInternAtom(wsDisplay, "WM_PROTOCOLS", False);
882 win->AtomsProtocols[0] = win->AtomDeleteWindow;
883 win->AtomsProtocols[1] = win->AtomTakeFocus;
884 win->AtomsProtocols[2] = win->AtomRolle;
885 /* --- */
886
887 win->WindowAttrib.background_pixel = BlackPixel(wsDisplay, wsScreen);
888 win->WindowAttrib.border_pixel = WhitePixel(wsDisplay, wsScreen);
889 win->WindowAttrib.colormap = XCreateColormap(wsDisplay, wsRootWin, win->VisualInfo.visual, AllocNone);
890 win->WindowAttrib.event_mask = StructureNotifyMask | FocusChangeMask |
891 ExposureMask | PropertyChangeMask |
892 EnterWindowMask | LeaveWindowMask |
893 VisibilityChangeMask |
894 KeyPressMask | KeyReleaseMask;
895
896 if ((c & wsHandleMouseButton))
897 win->WindowAttrib.event_mask |= ButtonPressMask | ButtonReleaseMask;
898
899 if ((c & wsHandleMouseMove))
900 win->WindowAttrib.event_mask |= PointerMotionMask;
901
902 win->WindowAttrib.cursor = win->wsCursor;
903 win->WindowAttrib.override_redirect = False;
904
905 if (p & wsOverredirect)
906 win->WindowAttrib.override_redirect = True;
907
908 win->WindowMask = CWBackPixel | CWBorderPixel |
909 CWColormap | CWEventMask | CWCursor |
910 CWOverrideRedirect;
911
912 win->WindowID = XCreateWindow(wsDisplay,
913 (win->Parent != 0 ? win->Parent : wsRootWin),
914 win->X, win->Y, win->Width, win->Height, win->BorderWidth,
915 win->VisualInfo.depth,
916 InputOutput,
917 win->VisualInfo.visual,
918 win->WindowMask, &win->WindowAttrib);
919
920 wsClassHint.res_name = "MPlayer";
921
922 wsClassHint.res_class = "MPlayer";
923 XSetClassHint(wsDisplay, win->WindowID, &wsClassHint);
924
925 wsSizeHint(win);
926
927 win->WMHints.flags = InputHint | StateHint;
928 win->WMHints.input = True;
929 win->WMHints.initial_state = NormalState;
930 XSetWMHints(wsDisplay, win->WindowID, &win->WMHints);
931
932 wsWindowDecoration(win, win->Decorations);
933 XStoreName(wsDisplay, win->WindowID, label);
934 XmbSetWMProperties(wsDisplay, win->WindowID, label, label, NULL, 0, NULL, NULL, NULL);
935
936 XSetWMProtocols(wsDisplay, win->WindowID, win->AtomsProtocols, 3);
937 XChangeProperty(wsDisplay, win->WindowID,
938 win->AtomLeaderClient,
939 XA_WINDOW, 32, PropModeReplace,
940 (unsigned char *)&LeaderWindow, 1);
941
942 wsTextProperty.value = label;
943 wsTextProperty.encoding = XA_STRING;
944 wsTextProperty.format = 8;
945 wsTextProperty.nitems = strlen(label);
946 XSetWMIconName(wsDisplay, win->WindowID, &wsTextProperty);
947
948 win->wGC = XCreateGC(wsDisplay, win->WindowID,
949 GCForeground | GCBackground,
950 &win->wGCV);
951
952 win->Visible = wsNo;
953 win->Focused = wsNo;
954 win->Mapped = wsNo;
955 win->Rolled = wsNo;
956
957 if (p & wsShowWindow) {
958 XMapWindow(wsDisplay, win->WindowID);
959 wsMapWait(win);
960 }
961
962 wsCreateImage(win, win->Width, win->Height);
963 /* End of creating -------------------------------------------------------------------------- */
964
965 {
966 int i;
967
968 for (i = 0; i < wsWLCount; i++)
969 if (wsWindowList[i] == NULL)
970 break;
971
972 if (i == wsWLCount) {
973 mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_TooManyOpenWindows);
974 mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
975 }
976
977 wsWindowList[i] = win;
978 }
979
980 XFlush(wsDisplay);
981 XSync(wsDisplay, False);
982
983 win->ReDraw = NULL;
984 win->MouseHandler = NULL;
985 win->KeyHandler = NULL;
986 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] window is created. ( %s ).\n", label);
987 }
988
989 void wsDestroyWindow(wsWindow *win)
990 {
991 int l;
992
993 l = wsSearch(win->WindowID);
994
995 if (l != -1)
996 wsWindowList[l] = NULL;
997
998 if (win->wsCursor != None) {
999 XFreeCursor(wsDisplay, win->wsCursor);
1000 win->wsCursor = None;
1001 }
1002
1003 XFreeGC(wsDisplay, win->wGC);
1004 XUnmapWindow(wsDisplay, win->WindowID);
1005 wsDestroyImage(win);
1006 XDestroyWindow(wsDisplay, win->WindowID);
1007 #if 0
1008 win->ReDraw = NULL;
1009 win->MouseHandler = NULL;
1010 win->KeyHandler = NULL;
1011 win->Visible = wsNo;
1012 win->Focused = wsNo;
1013 win->Mapped = wsNo;
1014 win->Rolled = wsNo;
1015 #endif
1016 }
1017
1018 void wsSetTitle(wsWindow *win, char *name)
1019 {
1020 XStoreName(wsDisplay, win->WindowID, name);
1021 }
1022
1023 void wsWindowDecoration(wsWindow *win, Bool decor)
1024 {
1025 MotifWmHints wsMotifWmHints;
1026
1027 wsMotifHints = XInternAtom(wsDisplay, "_MOTIF_WM_HINTS", 0);
1028
1029 if (wsMotifHints == None)
1030 return;
1031
1032 memset(&wsMotifWmHints, 0, sizeof(MotifWmHints));
1033 wsMotifWmHints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
1034
1035 if (decor) {
1036 wsMotifWmHints.functions = MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
1037 wsMotifWmHints.decorations = MWM_DECOR_ALL;
1038 }
1039
1040 XChangeProperty(wsDisplay, win->WindowID, wsMotifHints, wsMotifHints, 32,
1041 PropModeReplace, (unsigned char *)&wsMotifWmHints, 5);
1042 }
1043
1044 void wsSetShape(wsWindow *win, char *data)
1045 {
1046 #ifdef CONFIG_XSHAPE
1047 if (!wsUseXShape)
1048 return;
1049
1050 if (data) {
1051 win->Mask = XCreateBitmapFromData(wsDisplay, win->WindowID, data, win->Width, win->Height);
1052 XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, win->Mask, ShapeSet);
1053 XFreePixmap(wsDisplay, win->Mask);
1054 } else
1055 XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, None, ShapeSet);
1056 #endif
1057 }
1058
1059 /**
1060 * @brief Set differently sized icons to a window.
1061 *
1062 * This function sets the X icon hint as well as
1063 * the properties KWM_WIN_ICON and _NET_WM_ICON.
1064 *
1065 * @param display display
1066 * @param Win window
1067 * @param icon pointer to the icons
1068 */
1069 void wsSetIcon(Display *display, Window Win, guiIcon_t *icon)
1070 {
1071 XWMHints *wm;
1072 Atom iconatom;
1073 long data[2];
1074
1075 if (icon->normal) {
1076 wm = XGetWMHints(display, Win);
1077
1078 if (!wm)
1079 wm = XAllocWMHints();
1080
1081 wm->icon_pixmap = icon->normal;
1082 wm->icon_mask = icon->normal_mask;
1083 wm->flags |= IconPixmapHint | IconMaskHint;
1084
1085 XSetWMHints(display, Win, wm);
1086 XFree(wm);
1087 }
1088
1089 if (icon->small || icon->normal) {
1090 iconatom = XInternAtom(display, "KWM_WIN_ICON", False);
1091 data[0] = (icon->small ? icon->small : icon->normal);
1092 data[1] = (icon->small ? icon->small_mask : icon->normal_mask);
1093
1094 XChangeProperty(display, Win, iconatom, iconatom, 32, PropModeReplace, (unsigned char *)data, 2);
1095 }
1096
1097 if (icon->collection) {
1098 iconatom = XInternAtom(display, "_NET_WM_ICON", False);
1099 XChangeProperty(display, Win, iconatom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon->collection, icon->collection_size);
1100 }
1101 }
1102
1103 // ----------------------------------------------------------------------------------------------
1104 // Set window background to 'color'.
1105 // ----------------------------------------------------------------------------------------------
1106 void wsSetBackgroundRGB(wsWindow *win, int r, int g, int b)
1107 {
1108 int color = 0;
1109
1110 switch (wsOutMask) {
1111 case wsRGB32:
1112 case wsRGB24:
1113 color = (r << 16) + (g << 8) + b;
1114 break;
1115
1116 case wsBGR32:
1117 case wsBGR24:
1118 color = (b << 16) + (g << 8) + r;
1119 break;
1120
1121 case wsRGB16:
1122 PACK_RGB16(b, g, r, color);
1123 break;
1124
1125 case wsBGR16:
1126 PACK_RGB16(r, g, b, color);
1127 break;
1128
1129 case wsRGB15:
1130 PACK_RGB15(b, g, r, color);
1131 break;
1132
1133 case wsBGR15:
1134 PACK_RGB15(r, g, b, color);
1135 break;
1136 }
1137
1138 XSetWindowBackground(wsDisplay, win->WindowID, color);
1139 }
1140
1141 /**
1142 * @brief Clear the entire area in a window.
1143 *
1144 * @param win pointer to a ws window structure
1145 */
1146 void wsClearWindow(wsWindow *win)
1147 {
1148 XClearWindow(wsDisplay, win->WindowID);
1149 }
1150
1151 // ----------------------------------------------------------------------------------------------
1152 // Move window to x, y.
1153 // ----------------------------------------------------------------------------------------------
1154 void wsMoveWindow(wsWindow *win, Bool abs, int x, int y)
1155 {
1156 if (abs) {
1157 win->X = x;
1158 win->Y = y;
1159 } else
1160 wsWindowPosition(win, x, y, win->Width, win->Height);
1161
1162 wsSizeHint(win);
1163 XMoveWindow(wsDisplay, win->WindowID, win->X, win->Y);
1164 }
1165
1166 /**
1167 * @brief Move the window to the x and y position, but if it no longer fits
1168 * into the screen, reposition it towards the upper left.
1169 *
1170 * @param win pointer to a ws window structure
1171 * @param abs flag whether the position is real/absolute (True) or mock (False)
1172 * @param x x position of the window (real/absolute or mock)
1173 * @param y y position of the window (real/absolute or mock)
1174 */
1175 void wsMoveWindowWithin(wsWindow *win, Bool abs, int x, int y)
1176 {
1177 Bool fitting = True;
1178
1179 wsMoveWindow(win, abs, x, y);
1180
1181 if (win->X + win->Width + 1 > wsMaxX) {
1182 fitting = False;
1183 win->X = wsMaxX - win->Width;
1184
1185 if (win->X < 0)
1186 win->X = 0;
1187 }
1188
1189 if (win->Y + win->Height + 1 > wsMaxY) {
1190 fitting = False;
1191 win->Y = wsMaxY - win->Height;
1192
1193 if (win->Y < 0)
1194 win->Y = 0;
1195 }
1196
1197 if (!fitting)
1198 wsMoveWindow(win, True, win->X, win->Y);
1199 }
1200
1201 // ----------------------------------------------------------------------------------------------
1202 // Resize window to sx, sy.
1203 // ----------------------------------------------------------------------------------------------
1204 void wsResizeWindow(wsWindow *win, int sx, int sy)
1205 {
1206 win->Width = sx;
1207 win->Height = sy;
1208
1209 if (vo_wm_type == 0)
1210 XUnmapWindow(wsDisplay, win->WindowID);
1211
1212 wsSizeHint(win);
1213 XResizeWindow(wsDisplay, win->WindowID, sx, sy);
1214
1215 if (vo_wm_type == 0)
1216 XMapWindow(wsDisplay, win->WindowID);
1217 }
1218
1219 /**
1220 * @brief Switch window fullscreen state.
1221 *
1222 * Switch normal window to fullscreen and fullscreen window to normal.
1223 *
1224 * @param win pointer to a ws window structure
1225 */
1226 void wsFullScreen(wsWindow *win)
1227 {
1228 if (win->isFullScreen) {
1229 if (vo_fs_type & vo_wm_FULLSCREEN)
1230 /* window manager supports EWMH */
1231 vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_REMOVE);
1232 else {
1233 win->X = win->OldX;
1234 win->Y = win->OldY;
1235 win->Width = win->OldWidth;
1236 win->Height = win->OldHeight;
1237 }
1238
1239 win->isFullScreen = False;
1240 } else {
1241 if (vo_fs_type & vo_wm_FULLSCREEN)
1242 /* window manager supports EWMH */
1243 vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_ADD);
1244 else {
1245 win->OldX = win->X;
1246 win->OldY = win->Y;
1247 win->OldWidth = win->Width;
1248 win->OldHeight = win->Height;
1249 }
1250
1251 win->isFullScreen = True;
1252
1253 wsUpdateXineramaInfo(win);
1254 }
1255
1256 /* unknown window manager and obsolete option -fsmode used */
1257 if (vo_wm_type == 0 && !(vo_fsmode & 16)) {
1258 XUnmapWindow(wsDisplay, win->WindowID); // required for MWM
1259 XWithdrawWindow(wsDisplay, win->WindowID, wsScreen);
1260 }
1261
1262 /* restore window if window manager doesn't support EWMH */
1263 if (!(vo_fs_type & vo_wm_FULLSCREEN)) {
1264 wsSizeHint(win);
1265 wsWindowDecoration(win, win->Decorations && !win->isFullScreen);
1266 wsSetLayer(wsDisplay, win->WindowID, win->isFullScreen);
1267 XMoveResizeWindow(wsDisplay, win->WindowID, win->X, win->Y, win->Width, win->Height);
1268 }
1269
1270 /* some window managers lose ontop after fullscreen */
1271 if (!win->isFullScreen & vo_ontop)
1272 wsSetLayer(wsDisplay, win->WindowID, vo_ontop);
1273
1274 wsRaiseWindowTop(wsDisplay, win->WindowID);
1275 XFlush(wsDisplay);
1276 }
1277
1278 /**
1279 * @brief Iconify a window.
1280 *
1281 * @param win pointer to a ws window structure
1282 */
1283 void wsIconify(wsWindow *win)
1284 {
1285 XIconifyWindow(wsDisplay, win->WindowID, 0);
1327 } 1286 }
1328 1287
1329 void wsVisibleWindow(wsWindow *win, int show) 1288 void wsVisibleWindow(wsWindow *win, int show)
1330 { 1289 {
1331 switch (show) { 1290 switch (show) {
1346 } 1305 }
1347 1306
1348 XFlush(wsDisplay); 1307 XFlush(wsDisplay);
1349 } 1308 }
1350 1309
1351 void wsDestroyImage(wsWindow *win) 1310 /**
1352 { 1311 * @brief Map a window and raise it to the top.
1353 if (win->xImage) { 1312 *
1354 XDestroyImage(win->xImage); 1313 * @param display display
1355 1314 * @param Win window
1356 #ifdef HAVE_SHM 1315 */
1357 if (wsUseXShm) { 1316 void wsRaiseWindowTop(Display *display, Window Win)
1358 XShmDetach(wsDisplay, &win->Shminfo); 1317 {
1359 shmdt(win->Shminfo.shmaddr); 1318 XMapRaised(display, Win); // NOTE TO MYSELF: is that really enough?
1360 } 1319 XRaiseWindow(display, Win); // NOTE TO MYSELF: is that really enough?
1361 #endif 1320 }
1362 } 1321
1363 1322 // ----------------------------------------------------------------------------------------------
1364 win->xImage = NULL; 1323 // Move window to selected layer
1365 } 1324 // ----------------------------------------------------------------------------------------------
1366 1325
1326 /**
1327 * @brief Set the layer for a window.
1328 *
1329 * @param display display
1330 * @param Win window
1331 * @param fullscreen whether to set fullscreen or normal layer
1332 */
1333 void wsSetLayer(Display *display, Window Win, Bool fullscreen)
1334 {
1335 vo_x11_setlayer(display, Win, fullscreen);
1336 }
1337
1338 // ----------------------------------------------------------------------------------------------
1339 // Redraw screen.
1340 // ----------------------------------------------------------------------------------------------
1341 void wsPostRedisplay(wsWindow *win)
1342 {
1343 if (win->ReDraw) {
1344 win->State = wsWindowExpose;
1345 win->ReDraw();
1346 XFlush(wsDisplay);
1347 }
1348 }
1349
1350 // ----------------------------------------------------------------------------------------------
1351 // Put 'Image' to window.
1352 // ----------------------------------------------------------------------------------------------
1367 void wsCreateImage(wsWindow *win, int Width, int Height) 1353 void wsCreateImage(wsWindow *win, int Width, int Height)
1368 { 1354 {
1369 #ifdef HAVE_SHM 1355 #ifdef HAVE_SHM
1370 if (wsUseXShm) { 1356 if (wsUseXShm) {
1371 win->xImage = XShmCreateImage(wsDisplay, win->VisualInfo.visual, 1357 win->xImage = XShmCreateImage(wsDisplay, win->VisualInfo.visual,
1418 win->ImageData = (unsigned char *)win->xImage->data; 1404 win->ImageData = (unsigned char *)win->xImage->data;
1419 win->ImageDataw = (unsigned short int *)win->xImage->data; 1405 win->ImageDataw = (unsigned short int *)win->xImage->data;
1420 win->ImageDatadw = (unsigned int *)win->xImage->data; 1406 win->ImageDatadw = (unsigned int *)win->xImage->data;
1421 } 1407 }
1422 1408
1409 void wsDestroyImage(wsWindow *win)
1410 {
1411 if (win->xImage) {
1412 XDestroyImage(win->xImage);
1413
1414 #ifdef HAVE_SHM
1415 if (wsUseXShm) {
1416 XShmDetach(wsDisplay, &win->Shminfo);
1417 shmdt(win->Shminfo.shmaddr);
1418 }
1419 #endif
1420 }
1421
1422 win->xImage = NULL;
1423 }
1424
1425 void wsConvert(wsWindow *win, unsigned char *Image)
1426 {
1427 static struct SwsContext *sws_ctx;
1428 const uint8_t *src[4] = { Image, NULL, NULL, NULL };
1429 int src_stride[4] = { 4 * win->xImage->width, 0, 0, 0 };
1430 uint8_t *dst[4] = { win->ImageData, NULL, NULL, NULL };
1431 int dst_stride[4];
1432 int i;
1433
1434 sws_ctx = sws_getCachedContext(sws_ctx, win->xImage->width, win->xImage->height, PIX_FMT_RGB32,
1435 win->xImage->width, win->xImage->height, out_pix_fmt,
1436 SWS_POINT, NULL, NULL, NULL);
1437 av_image_fill_linesizes(dst_stride, out_pix_fmt, win->xImage->width);
1438 sws_scale(sws_ctx, src, src_stride, 0, win->xImage->height, dst, dst_stride);
1439
1440 if (!wsNonNativeOrder)
1441 return;
1442
1443 switch (win->xImage->bits_per_pixel) {
1444 case 32:
1445 {
1446 uint32_t *d = (uint32_t *)win->ImageData;
1447
1448 for (i = 0; i < win->xImage->width * win->xImage->height; i++)
1449 d[i] = bswap_32(d[i]);
1450
1451 break;
1452 }
1453
1454 case 16:
1455 case 15:
1456 {
1457 uint16_t *d = (uint16_t *)win->ImageData;
1458
1459 for (i = 0; i < win->xImage->width * win->xImage->height; i++)
1460 d[i] = bswap_16(d[i]);
1461
1462 break;
1463 }
1464 }
1465 }
1466
1467 void wsPutImage(wsWindow *win)
1468 {
1469 #ifdef HAVE_SHM
1470 if (wsUseXShm) {
1471 XShmPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage,
1472 0, 0,
1473 (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2,
1474 win->xImage->width, win->xImage->height, 0);
1475 } else
1476 #endif
1477 {
1478 XPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage,
1479 0, 0,
1480 (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2,
1481 win->xImage->width, win->xImage->height);
1482 }
1483 }
1484
1423 void wsResizeImage(wsWindow *win, int Width, int Height) 1485 void wsResizeImage(wsWindow *win, int Width, int Height)
1424 { 1486 {
1425 wsDestroyImage(win); 1487 wsDestroyImage(win);
1426 wsCreateImage(win, Width, Height); 1488 wsCreateImage(win, Width, Height);
1427 } 1489 }
1428 1490
1429 int wsGetOutMask(void) 1491 // ----------------------------------------------------------------------------------------------
1430 { 1492 // Show / hide mouse cursor.
1431 if ((wsDepthOnScreen == 32) && (wsRedMask == 0xff0000) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0x0000ff)) 1493 // ----------------------------------------------------------------------------------------------
1432 return wsRGB32; 1494 void wsVisibleMouse(wsWindow *win, int m)
1433 1495 {
1434 if ((wsDepthOnScreen == 32) && (wsRedMask == 0x0000ff) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0xff0000)) 1496 switch (m) {
1435 return wsBGR32; 1497 case wsShowMouseCursor:
1436 1498
1437 if ((wsDepthOnScreen == 24) && (wsRedMask == 0xff0000) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0x0000ff)) 1499 if (win->wsCursor != None) {
1438 return wsRGB24; 1500 XFreeCursor(wsDisplay, win->wsCursor);
1439 1501 win->wsCursor = None;
1440 if ((wsDepthOnScreen == 24) && (wsRedMask == 0x0000ff) && (wsGreenMask == 0x00ff00) && (wsBlueMask == 0xff0000)) 1502 }
1441 return wsBGR24; 1503
1442 1504 XDefineCursor(wsDisplay, win->WindowID, 0);
1443 if ((wsDepthOnScreen == 16) && (wsRedMask == 0xf800) && (wsGreenMask == 0x7e0) && (wsBlueMask == 0x1f)) 1505 break;
1444 return wsRGB16; 1506
1445 1507 case wsHideMouseCursor:
1446 if ((wsDepthOnScreen == 16) && (wsRedMask == 0x1f) && (wsGreenMask == 0x7e0) && (wsBlueMask == 0xf800)) 1508
1447 return wsBGR16; 1509 win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0);
1448 1510 XDefineCursor(wsDisplay, win->WindowID, win->wsCursor);
1449 if ((wsDepthOnScreen == 15) && (wsRedMask == 0x7c00) && (wsGreenMask == 0x3e0) && (wsBlueMask == 0x1f)) 1511 break;
1450 return wsRGB15; 1512 }
1451 1513
1452 if ((wsDepthOnScreen == 15) && (wsRedMask == 0x1f) && (wsGreenMask == 0x3e0) && (wsBlueMask == 0x7c00)) 1514 XFlush(wsDisplay);
1453 return wsBGR15;
1454
1455 return 0;
1456 } 1515 }
1457 1516
1458 /** 1517 /**
1459 * @brief Clear the entire area in a window. 1518 * @brief Handle automatic hiding of the cursor.
1460 *
1461 * @param win pointer to a ws window structure
1462 */ 1519 */
1463 void wsClearWindow(wsWindow *win) 1520 void wsAutohideCursor(void)
1464 { 1521 {
1465 XClearWindow(wsDisplay, win->WindowID); 1522 if (mouse_win && (GetTimerMS() - mouse_time >= MOUSEHIDE_DELAY)) {
1466 } 1523 wsVisibleMouse(mouse_win, wsHideMouseCursor);
1467 1524 mouse_win = NULL;
1468 void wsSetTitle(wsWindow *win, char *name) 1525 }
1469 { 1526 }
1470 XStoreName(wsDisplay, win->WindowID, name);
1471 }
1472
1473 void wsSetShape(wsWindow *win, char *data)
1474 {
1475 #ifdef CONFIG_XSHAPE
1476 if (!wsUseXShape)
1477 return;
1478
1479 if (data) {
1480 win->Mask = XCreateBitmapFromData(wsDisplay, win->WindowID, data, win->Width, win->Height);
1481 XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, win->Mask, ShapeSet);
1482 XFreePixmap(wsDisplay, win->Mask);
1483 } else
1484 XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, None, ShapeSet);
1485 #endif
1486 }
1487
1488 /**
1489 * @brief Set differently sized icons to a window.
1490 *
1491 * This function sets the X icon hint as well as
1492 * the properties KWM_WIN_ICON and _NET_WM_ICON.
1493 *
1494 * @param display display
1495 * @param Win window
1496 * @param icon pointer to the icons
1497 */
1498 void wsSetIcon(Display *display, Window Win, guiIcon_t *icon)
1499 {
1500 XWMHints *wm;
1501 Atom iconatom;
1502 long data[2];
1503
1504 if (icon->normal) {
1505 wm = XGetWMHints(display, Win);
1506
1507 if (!wm)
1508 wm = XAllocWMHints();
1509
1510 wm->icon_pixmap = icon->normal;
1511 wm->icon_mask = icon->normal_mask;
1512 wm->flags |= IconPixmapHint | IconMaskHint;
1513
1514 XSetWMHints(display, Win, wm);
1515 XFree(wm);
1516 }
1517
1518 if (icon->small || icon->normal) {
1519 iconatom = XInternAtom(display, "KWM_WIN_ICON", False);
1520 data[0] = (icon->small ? icon->small : icon->normal);
1521 data[1] = (icon->small ? icon->small_mask : icon->normal_mask);
1522
1523 XChangeProperty(display, Win, iconatom, iconatom, 32, PropModeReplace, (unsigned char *)data, 2);
1524 }
1525
1526 if (icon->collection) {
1527 iconatom = XInternAtom(display, "_NET_WM_ICON", False);
1528 XChangeProperty(display, Win, iconatom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon->collection, icon->collection_size);
1529 }
1530 }