Package dtk :: Package ui :: Module mplayer_window

Source Code for Module dtk.ui.mplayer_window

  1  #! /usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (C) 2011 ~ 2012 Deepin, Inc. 
  5  #               2011 ~ 2012 Wang Yong 
  6  #  
  7  # Author:     Wang Yong <lazycat.manatee@gmail.com> 
  8  # Maintainer: Wang Yong <lazycat.manatee@gmail.com> 
  9  #  
 10  # This program is free software: you can redistribute it and/or modify 
 11  # it under the terms of the GNU General Public License as published by 
 12  # the Free Software Foundation, either version 3 of the License, or 
 13  # any later version. 
 14  #  
 15  # This program is distributed in the hope that it will be useful, 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18  # GNU General Public License for more details. 
 19  #  
 20  # You should have received a copy of the GNU General Public License 
 21  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 22   
 23  from constant import EDGE_DICT 
 24  from draw import draw_window_shadow, draw_window_frame 
 25  from skin_config import skin_config 
 26  from theme import ui_theme 
 27  import cairo 
 28  import gobject 
 29  import gtk 
 30  from utils import (cairo_state, propagate_expose, resize_window,  
 31                     set_cursor, get_event_root_coords, enable_shadow,  
 32                     is_double_click, move_window) 
 33   
34 -class MplayerWindow(gtk.Window):
35 """ 36 Special Window class for mplayer. 37 38 Generally speaking, compared with Window class, it uses a different shadow mechanism. 39 40 @undocumented: adjust_window_shadow 41 @undocumented: get_cursor_type 42 @undocumented: expose_window 43 @undocumented: shape_window 44 @undocumented: shape_window_frame 45 @undocumented: shape_window_shadow 46 @undocumented: expose_window_background 47 @undocumented: expose_window_shadow 48 @undocumented: expose_window_frame 49 @undocumented: motion_notify 50 @undocumented: double_click_window 51 @undocumented: monitor_window_state 52 """ 53
54 - def __init__(self, 55 enable_resize=False, 56 shadow_radius=6, 57 window_type=gtk.WINDOW_TOPLEVEL):
58 """ 59 Initialise the Window class. 60 61 @param enable_resize: If True, the window will be set resizable. By default, it's False. 62 @param shadow_radius: The radius of the shadow. 63 @param window_type: A flag of type gtk._gtk.WindowType, which indicates the type of the window. By default, it's gtk.WINDOW_TOPLEVEL. 64 """ 65 # Init. 66 gtk.Window.__init__(self, window_type) 67 skin_config.wrap_skin_window(self) 68 self.set_decorated(False) 69 self.add_events(gtk.gdk.ALL_EVENTS_MASK) 70 self.shadow_radius = shadow_radius 71 self.frame_radius = 2 72 self.shadow_is_visible = True 73 self.enable_resize = enable_resize 74 self.window_frame = gtk.VBox() 75 self.add(self.window_frame) 76 self.shape_flag = True 77 78 # FIXME: Because mplayer don't allowed window redirect colormap to screen. 79 # We build shadow window to emulate it, but shadow's visual effect 80 # is not good enough, so we disable shadow temporary for future fixed. 81 self.shadow_visible = False 82 83 if enable_shadow(self) and self.shadow_visible: 84 self.shadow_padding = self.shadow_radius - self.frame_radius 85 else: 86 self.shadow_padding = 0 87 88 # Init shadow window. 89 if enable_shadow(self) and self.shadow_visible: 90 self.window_shadow = gtk.Window(gtk.WINDOW_TOPLEVEL) 91 self.window_shadow.add_events(gtk.gdk.ALL_EVENTS_MASK) 92 self.window_shadow.set_decorated(False) 93 self.window_shadow.set_colormap(gtk.gdk.Screen().get_rgba_colormap()) 94 self.window_shadow.set_transient_for(self) 95 self.window_shadow.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_MENU) 96 97 # Handle signal. 98 self.connect_after("expose-event", self.expose_window) 99 self.connect("size-allocate", self.shape_window) 100 self.connect("window-state-event", self.monitor_window_state) 101 self.connect("configure-event", self.adjust_window_shadow) 102 103 if enable_shadow(self) and self.shadow_visible: 104 self.window_shadow.connect("expose-event", self.expose_window_shadow) 105 self.window_shadow.connect("size-allocate", self.shape_window_shadow) 106 self.window_shadow.connect("button-press-event", self.resize_window) 107 self.window_shadow.connect("motion-notify-event", self.motion_notify)
108
109 - def adjust_window_shadow(self, widget, event):
110 """ 111 Internal function to adjust postion and size of the shadow of the window. 112 113 @param widget: the widget of type gtk.Widget. 114 @param event: the event of gtk.gdk.Event. 115 """ 116 if enable_shadow(self) and self.shadow_visible: 117 (x, y) = self.get_position() 118 (width, height) = self.get_size() 119 120 self.window_shadow.get_window().move_resize( 121 x - self.shadow_padding, y - self.shadow_padding, 122 width + self.shadow_padding * 2, height + self.shadow_padding * 2 123 )
124
125 - def show_window(self):
126 """ 127 Show the window. 128 """ 129 self.show_all() 130 131 if enable_shadow(self) and self.shadow_visible: 132 self.window_shadow.show_all()
133
134 - def expose_window(self, widget, event):
135 """ 136 Internal function to expose the window. 137 138 @param widget: A window of type Gtk.Widget. 139 @param event: The expose event of type gtk.gdk.Event. 140 141 @return: Always return True. 142 """ 143 # Init. 144 cr = widget.window.cairo_create() 145 rect = widget.allocation 146 x, y, w, h = rect.x, rect.y, rect.width, rect.height 147 148 # Clear color to transparent window. 149 cr.set_source_rgba(0.0, 0.0, 0.0, 0.0) 150 cr.set_operator(cairo.OPERATOR_SOURCE) 151 cr.paint() 152 153 # Draw background. 154 with cairo_state(cr): 155 cr.rectangle(x + 2, y, w - 4, 1) 156 cr.rectangle(x + 1, y + 1, w - 2, 1) 157 cr.rectangle(x, y + 2, w, h - 4) 158 cr.rectangle(x + 2, y + h - 1, w - 4, 1) 159 cr.rectangle(x + 1, y + h - 2, w - 2, 1) 160 161 cr.clip() 162 163 skin_config.render_background(cr, self, x, y) 164 165 # Draw mask. 166 self.draw_mask(cr, x, y, w, h) 167 168 # Draw window frame. 169 draw_window_frame(cr, x, y, w, h, 170 ui_theme.get_alpha_color("window_frame_outside_1"), 171 ui_theme.get_alpha_color("window_frame_outside_2"), 172 ui_theme.get_alpha_color("window_frame_outside_3"), 173 ui_theme.get_alpha_color("window_frame_inside_1"), 174 ui_theme.get_alpha_color("window_frame_inside_2"), 175 ) 176 177 # Propagate expose. 178 propagate_expose(widget, event) 179 180 return True
181
182 - def draw_mask(self, cr, x, y, w, h):
183 ''' 184 Draw mask interface, you should implement it you own. 185 186 @param cr: Cairo context. 187 @param x: X coordinate of draw area. 188 @param y: Y coordinate of draw area. 189 @param w: Width of draw area. 190 @param h: Height of draw area. 191 ''' 192 pass
193
194 - def set_window_shape(self, shape_flag):
195 """ 196 Enable window shape. 197 198 @param shape_flag: The flag that indicates the shape. 199 """ 200 self.shape_flag = shape_flag 201 self.shape_window(self, self.get_allocation())
202
203 - def shape_window(self, widget, rect):
204 """ 205 Internal function to draw the shaped window. 206 207 @param widget: A widget of type gtk.Widget. 208 @param rect: The bounding region of the window. 209 """ 210 if rect.width > 0 and rect.height > 0: 211 # Init. 212 x, y, w, h = rect.x, rect.y, rect.width, rect.height 213 bitmap = gtk.gdk.Pixmap(None, w, h, 1) 214 cr = bitmap.cairo_create() 215 216 # Clear the bitmap 217 cr.set_source_rgb(0.0, 0.0, 0.0) 218 cr.set_operator(cairo.OPERATOR_CLEAR) 219 cr.paint() 220 221 # Draw our shape into the bitmap using cairo. 222 cr.set_source_rgb(1.0, 1.0, 1.0) 223 cr.set_operator(cairo.OPERATOR_OVER) 224 225 if not self.shape_flag: 226 # Don't clip corner when window is fullscreen state. 227 cr.rectangle(x, y, w, h) 228 elif self.window != None and self.window.get_state() == gtk.gdk.WINDOW_STATE_FULLSCREEN: 229 # Don't clip corner when window is fullscreen state. 230 cr.rectangle(x, y, w, h) 231 else: 232 cr.rectangle(x + 2, y, w - 4, 1) 233 cr.rectangle(x + 1, y + 1, w - 2, 1) 234 cr.rectangle(x, y + 2, w, h - 4) 235 cr.rectangle(x + 1, y + h - 2, w - 2, 1) 236 cr.rectangle(x + 2, y + h - 1, w - 4, 1) 237 cr.fill() 238 239 # Shape with given mask. 240 widget.shape_combine_mask(bitmap, 0, 0) 241 242 # Redraw whole window. 243 self.queue_draw() 244 245 if enable_shadow(self) and self.shadow_visible: 246 self.window_shadow.queue_draw()
247
248 - def shape_window_shadow(self, widget, rect):
249 """ 250 Internal function to draw the shaped window's shadow. 251 252 @param widget: A widget of type gtk.Widget. 253 @param rect: The bounding region of the window. 254 """ 255 if rect.width > 0 and rect.height > 0: 256 # Init. 257 x, y, w, h = rect.x, rect.y, rect.width, rect.height 258 bitmap = gtk.gdk.Pixmap(None, w, h, 1) 259 cr = bitmap.cairo_create() 260 261 # Clear the bitmap 262 cr.set_source_rgb(0.0, 0.0, 0.0) 263 cr.set_operator(cairo.OPERATOR_CLEAR) 264 cr.paint() 265 266 # Draw our shape into the bitmap using cairo. 267 cr.set_source_rgb(1.0, 1.0, 1.0) 268 cr.set_operator(cairo.OPERATOR_OVER) 269 270 # Four side. 271 cr.rectangle(x, y, w, self.shadow_padding) 272 cr.rectangle(x, y + self.shadow_padding, self.shadow_padding, h - self.shadow_padding * 2) 273 cr.rectangle(x + w - self.shadow_padding, y + self.shadow_padding, self.shadow_padding, h - self.shadow_padding * 2) 274 cr.rectangle(x, y + h - self.shadow_padding, w, self.shadow_padding) 275 276 # Four 2-pixel rectange. 277 cr.rectangle(x + self.shadow_padding, y + self.shadow_padding, 2, 1) 278 cr.rectangle(x + w - self.shadow_padding - 2, y + self.shadow_padding, 2, 1) 279 cr.rectangle(x + self.shadow_padding, y + h - self.shadow_padding - 1, 2, 1) 280 cr.rectangle(x + w - self.shadow_padding - 2, y + h - self.shadow_padding - 1, 2, 1) 281 282 # Four 1-pixel rectange. 283 cr.rectangle(x + self.shadow_padding, y + self.shadow_padding + 1, 1, 1) 284 cr.rectangle(x + w - self.shadow_padding - 1, y + self.shadow_padding + 1, 1, 1) 285 cr.rectangle(x + self.shadow_padding, y + h - self.shadow_padding - 2, 1, 1) 286 cr.rectangle(x + w - self.shadow_padding - 1, y + h - self.shadow_padding - 2, 1, 1) 287 288 cr.fill() 289 290 # Shape with given mask. 291 widget.shape_combine_mask(bitmap, 0, 0) 292 293 # Redraw whole window. 294 self.queue_draw() 295 296 if enable_shadow(self) and self.shadow_visible: 297 self.window_shadow.queue_draw()
298
299 - def expose_window_shadow(self, widget, event):
300 """ 301 Internal fucntion to expose the window shadow. 302 303 @param widget: the window of gtk.Widget. 304 @param event: The expose event of type gtk.gdk.Event. 305 """ 306 if self.shadow_is_visible: 307 # Init. 308 cr = widget.window.cairo_create() 309 rect = widget.allocation 310 x, y, w, h = rect.x, rect.y, rect.width, rect.height 311 312 # Clear color to transparent window. 313 cr.set_source_rgba(0.0, 0.0, 0.0, 0.0) 314 cr.set_operator(cairo.OPERATOR_SOURCE) 315 cr.paint() 316 317 # Draw window shadow. 318 draw_window_shadow(cr, x, y, w, h, self.shadow_radius, self.shadow_padding, ui_theme.get_shadow_color("window_shadow"))
319
320 - def hide_shadow(self):
321 """ 322 Hide the window shadow. 323 """ 324 self.shadow_is_visible = False 325 326 if enable_shadow(self) and self.shadow_visible: 327 self.window_shadow.hide_all()
328
329 - def show_shadow(self):
330 """ 331 Show the window shadow. 332 """ 333 self.shadow_is_visible = True 334 335 if enable_shadow(self) and self.shadow_visible: 336 self.window_shadow.show_all()
337
339 """ 340 An interface which indicates whether the window could be maximized, you should implement this function you own. 341 @return: Always return False. 342 """ 343 return False
344
345 - def monitor_window_state(self, widget, event):
346 """ 347 Monitor window state, add shadow when window at maximized or fullscreen status. Otherwise hide shadow. 348 349 @param widget: The window of type gtk.Widget. 350 @param event: The event of gtk.gdk.Event. 351 """ 352 window_state = self.window.get_state() 353 if window_state in [gtk.gdk.WINDOW_STATE_MAXIMIZED, gtk.gdk.WINDOW_STATE_FULLSCREEN]: 354 self.hide_shadow() 355 356 if self.is_disable_window_maximized(): 357 self.unmaximize() 358 else: 359 self.show_shadow() 360 361 self.adjust_window_shadow(widget, event)
362
363 - def min_window(self):
364 """ 365 Minimize the window. Make it iconified. 366 """ 367 self.iconify()
368
369 - def toggle_max_window(self):
370 """ 371 Toggle the window size between maximized size and normal size. 372 """ 373 window_state = self.window.get_state() 374 if window_state == gtk.gdk.WINDOW_STATE_MAXIMIZED: 375 self.unmaximize() 376 else: 377 self.maximize()
378
379 - def toggle_fullscreen_window(self):
380 """ 381 Toggle the window between fullscreen mode and normal size. 382 """ 383 window_state = self.window.get_state() 384 if window_state == gtk.gdk.WINDOW_STATE_FULLSCREEN: 385 self.unfullscreen() 386 else: 387 self.fullscreen()
388
389 - def close_window(self):
390 """ 391 Close the window. Send the destroy signal to the program. 392 393 @return: Always return False. 394 """ 395 # Hide window immediately when user click close button, 396 # user will feeling this software very quick, ;p 397 self.hide_all() 398 399 self.emit("destroy") 400 401 return False
402
403 - def resize_window(self, widget, event):
404 """ 405 Resize the window. 406 407 @param widget: The window of type gtk.Widget. 408 @param event: A signal of type gtk.gdk.Event. 409 """ 410 if self.enable_resize: 411 edge = self.get_edge() 412 if edge != None: 413 resize_window(self, event, self, edge)
414
415 - def add_move_event(self, widget):
416 """ 417 Add move event callback. 418 419 @param widget: A widget of type gtk.Widget. 420 """ 421 widget.connect("button-press-event", lambda w, e: move_window(w, e, self))
422
423 - def add_toggle_event(self, widget):
424 """ 425 Add toggle event callback. 426 427 @param widget: A widget of type gtk.Widget. 428 """ 429 widget.connect("button-press-event", self.double_click_window)
430
431 - def double_click_window(self, widget, event):
432 """ 433 Internal function to double click event handler of the window. It will maximize the window. 434 435 @param widget: A widget of type gtk.Widget. 436 @param event: A event of type gtk.gdk.Event. 437 438 @return: Always return False. 439 """ 440 if is_double_click(event): 441 self.toggle_max_window() 442 443 return False
444
445 - def motion_notify(self, widget, event):
446 """ 447 Internal callback for `motion-notify-event` signal. 448 449 @param widget: A widget of gtk.Widget. 450 @param event: The motion-notify-event of type gtk.gdk.Event 451 """ 452 if self.enable_resize and self.shadow_is_visible: 453 self.cursor_type = self.get_cursor_type(event) 454 set_cursor(self.window_shadow, self.cursor_type)
455
456 - def get_edge(self):
457 """ 458 Get the edge which the cursor is on, according to the cursor type. 459 460 @return: If there is a corresponding cursor type, return an instance of gtk.gdk.WindowEdge, else return None. 461 """ 462 if EDGE_DICT.has_key(self.cursor_type): 463 return EDGE_DICT[self.cursor_type] 464 else: 465 return None
466
467 - def get_cursor_type(self, event):
468 """ 469 Get the cursor position. 470 471 @param event: An event of type gtk.gdk.Event. 472 473 @return: If the cursor is on the frame of the window, return the cursor position. Otherwise return None. 474 """ 475 # Get event coordinate. 476 (ex, ey) = get_event_root_coords(event) 477 478 # Get window allocation. 479 rect = self.window_shadow.get_allocation() 480 (wx, wy) = self.window_shadow.get_position() 481 ww = rect.width 482 wh = rect.height 483 484 # Return cursor position. 485 if wx <= ex <= wx + self.shadow_padding: 486 if wy <= ey <= wy + self.shadow_padding * 2: 487 return gtk.gdk.TOP_LEFT_CORNER 488 elif wy + wh - (self.shadow_padding * 2) <= ey <= wy + wh: 489 return gtk.gdk.BOTTOM_LEFT_CORNER 490 elif wy + self.shadow_padding < ey < wy + wh - self.shadow_padding: 491 return gtk.gdk.LEFT_SIDE 492 else: 493 return None 494 elif wx + ww - self.shadow_padding <= ex <= wx + ww: 495 if wy <= ey <= wy + self.shadow_padding * 2: 496 return gtk.gdk.TOP_RIGHT_CORNER 497 elif wy + wh - (self.shadow_padding * 2) <= ey <= wy + wh: 498 return gtk.gdk.BOTTOM_RIGHT_CORNER 499 elif wy + self.shadow_padding < ey < wy + wh - self.shadow_padding: 500 return gtk.gdk.RIGHT_SIDE 501 else: 502 return None 503 elif wx + self.shadow_padding < ex < wx + ww - self.shadow_padding: 504 if wy <= ey <= wy + self.shadow_padding: 505 return gtk.gdk.TOP_SIDE 506 elif wy + wh - self.shadow_padding <= ey <= wy + wh: 507 return gtk.gdk.BOTTOM_SIDE 508 else: 509 return None 510 else: 511 return None
512
513 - def get_shadow_size(self):
514 """ 515 Get the shadow size. 516 517 @return: Always return (0, 0) 518 """ 519 return (0, 0)
520 521 gobject.type_register(MplayerWindow) 522 523 if __name__ == "__main__": 524 window = MplayerWindow() 525 window.connect("destroy", lambda w: gtk.main_quit()) 526 window.set_size_request(500, 500) 527 window.move(100, 100) 528 # window.window_frame.add(gtk.Button("Linux Deepin")) 529 window.show_window() 530 531 gtk.main() 532